first commit

This commit is contained in:
2018-08-01 16:00:05 +02:00
commit 944fd76206
3205 changed files with 356767 additions and 0 deletions
+170
View File
@@ -0,0 +1,170 @@
# v2.7.1
## 12/05/2017
1. [](#new)
* Added new `onEmailSend()` event hook before sending [#70](https://github.com/getgrav/grav-plugin-email/pull/70)
1. [](#improved)
* Added examples of setting up Email plugin with various SMTP providers
* Updated RU language [#60](https://github.com/getgrav/grav-plugin-email/pull/60)
* Updated to SwiftMailer v5.4.8
# v2.7.0
## 10/26/2017
1. [](#improved)
* Now uses a dedicated `logs/email.log` file when `debug: true`
* Improved the README.txt file with examples, and troubleshooting
* Changed default engine to `sendmail` as `mail` is deprecated and not functioning [swiftmailer#866](https://github.com/swiftmailer/swiftmailer/issues/866}
# v2.6.2
## 09/30/2017
1. [](#improved)
* Removed extraneous files from vendor folder
# v2.6.1
## 09/07/2017
1. [](#improved)
* Improved the error message when missing `from` in the configuration
* Silently catch malformed email exceptions
# v2.6.0
## 05/22/2017
1. [](#improved)
* Inherit options from plugin configuration [#39](https://github.com/getgrav/grav-plugin-email/pull/39)
1. [](#bugfix)
* Also process translation on the email subject [https://github.com/getgrav/grav-plugin-comments/issues/38](https://github.com/getgrav/grav-plugin-comments/issues/38)
# v2.5.3
## 01/03/2017
1. [](#improved)
* Updated to SwiftMailer 5.4.5 [#45](https://github.com/getgrav/grav-plugin-email/issues/45)
# v2.5.2
## 12/13/2016
1. [](#new)
* RC released as stable
# v2.5.2-rc.1
## 11/26/2016
1. [](#new)
* Added a new `process_markdown` option for emails in forms
1. [](#improved)
* Improved the `Utils::sendEmail()` method to take the email type as an option
# v2.5.1
## 10/19/2016
1. [](#improved)
* CLI command will fallback to use the `to` from email plugin config if not provided
* Explicit Composer based class loader to fix issues with class case
# v2.5.0
## 09/07/2016
1. [](#new)
* Added a new `bin/plugin email test-email` CLI command
1. [](#improved)
* Moved Email `Utils` class from Login to Email plugin
* Provide a sample base `email/base.html.twig` template for emails
1. [](#bugfix)
* Fix handling attachments with the updated file upload field
# v2.4.3
## 08/16/2016
1. [](#improved)
* Added Russian translation
* Updated Swiftmailer to 5.4.3 [#37](https://github.com/getgrav/grav-plugin-email/issues/37)
# v2.4.2
## 08/10/2016
1. [](#improved)
* Added Croatian translation
# v2.4.1
## 07/14/2016
1. [](#improved)
* Allow multiple email recipients (comma separated) [#31](https://github.com/getgrav/grav-plugin-email/issues/31)
* Added Danish and Spanish translations
# v2.4.0
## 05/11/2016
1. [](#improved)
* Now includes Swiftmailer v5.4.2 which introduces a number of bug fixes and improvements
1. [](#bugfix)
* Correct `starttls` implementation, bundled in TLS
# v2.3.0
## 04/20/2016
1. [](#improved)
* Added debug option to enable logging on SwiftMailer.
* Updated SwiftMailer from v5.1.0 to v5.4.1.
* Added an option in the Admin settings to enable `starttls`
1. [](#bugfix)
* Correctly name TLS in the Admin settings, the label was `TTS` (but the value was correctly named `tls`)
# v2.2.0
## 02/05/2016
1. [](#new)
* Allow to send attachments in forms
* Added French translation
1. [](#improved)
* Throw an exception when trying to send emails without a `from` or `to` parameters setup, to intercept less meaningful errors and provide a better description on how to fix the problem
* Changed SMTP password in admin to use a password field instead of plain text
# v2.1.0
## 12/18/2015
1. [](#new)
* Added missing `content_type` to email.yaml
* Added default values for CC and BCC
1. [](#improved)
* Improved documentation of new email params in `README.md`
* Moved config setting of `mailer.default` to `mailer.engine`
# v2.0.0
## 12/11/2015
1. [](#new)
* Added support for from/sender name (Thomas Keitel)
* Added support for message content type (Thomas Keitel)
* Added support for reply addresses (Thomas Keitel)
* Added support for CC/BCC (Thomas Keitel)
* Added support for multiple body parts (Thomas Keitel)
1. [](#bugfix)
* Fix email engine selection (z38)
# v1.0.0
## 11/20/2015
1. [](#bugfix)
* Fix for issue with no body parameter specified
# v0.2.1
## 09/11/2015
1. [](#bugfix)
* Fix onFormProcessed event
# v0.2.0
## 08/11/2015
1. [](#improved)
* Disable `enable` in admin
# v0.1.0
## 08/04/2015
1. [](#new)
* ChangeLog started...
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Grav
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.
+373
View File
@@ -0,0 +1,373 @@
# Grav Email Plugin
The **email plugin** for [Grav](http://github.com/getgrav/grav) adds the ability to send email. This is particularly useful for the **admin** and **login** plugins.
# Installation
The email plugin is easy to install with GPM.
```
$ bin/gpm install email
```
# Configuration
By default, the plugin uses PHP Mail as the mail engine.
```
enabled: true
from:
from_name:
to:
to_name:
mailer:
engine: sendmail
smtp:
server: localhost
port: 25
encryption: none
user: ''
password: ''
sendmail:
bin: '/usr/sbin/sendmail -bs'
content_type: text/html
debug: false
```
You can configure the Email plugin by using the Admin plugin, navigating to the Plugins list and choosing `Email`.
That's the easiest route. Or you can also alter the Plugin configuration by copying the `user/plugins/email/email.yaml` file into `user/config/plugins/email.yaml` and make your modifications there.
The first setting you'd likely change is your `Email from` / `Email to` names and emails.
Also, you'd likely want to setup a SMTP server instead of using PHP Mail, as the latter is not 100% reliable and you might experience problems with emails.
> NOTE: `engine: mail` has been deprecated from the SwiftMail library that this plugin uses as it does not funtion at all. Please use `smtp` if at all possibe, and `sendmail` if SMTP is not an option.
### Mailtrap.io
A good way to test emails is to use a SMTP server service that's built for testing emails, for example [https://mailtrap.io](https://mailtrap.io)
Setup the Email plugin to use that SMTP server with the fake inbox data. For example enter this configuration in `user/config/plugins/email.yaml` or through the Admin panel:
```
mailer:
engine: smtp
smtp:
server: mailtrap.io
port: 2525
encryption: none
user: YOUR_MAILTRAP_INBOX_USER
password: YOUR_MAILTRAP_INBOX_PASSWORD
```
That service will intercept emails and show them on their web-based interface instead of sending them for real.
You can try and fine tune the emails there while testing.
### Google Email
A popular option for sending email is to simply use your Google Accounts SMTP server. To set this up you will need to do 2 things first:
1. Enable IMAP in your Gmail `Settings` -> `Forwarding and POP/IMAP` -> `IMAP Access`
2. Enable `Less secure apps` in your [user account settings](https://myaccount.google.com/lesssecureapps)
3. If you have 2-factor authentication, you will need to create a unique application password to use rather than your personal password
Then configure the Email plugin:
```
mailer:
engine: smtp
smtp:
server: smtp.gmail.com
port: 465
encryption: ssl
user: 'YOUR_GOOGLE_EMAIL_ADDRESS'
password: 'YOUR_GOOGLE_PASSWORD'
```
> NOTE: Check your email sending limits: https://support.google.com/a/answer/166852?hl=en
#### Sparkpost
Generous email sending limits even in the free tier, and simple setup, make [Sparkpost](https://www.sparkpost.com) a great option for email sending. You just need to create an account, then setup a verified sending domain. Sparkpost does a nice job of making this process very easy and undertandable. Then just click on the SMTP Relay option to get your details for the configuration:
```
mailer:
engine: smtp
smtp:
server: smtp.sparkpostmail.com
port: 587
encryption: tls
user: 'SMTP_Injection'
password: 'SEND_EMAIL_API_KEY'
```
Then try sending a test email...
#### Sendgrid
[Sendgrid](https://sendgrid.com) offers a very easy-to-setup serivce with 100 emails/day for free. The next level allows you to send 40k/email a day for just $10/month. Configuration is pretty simple, just create an account, then click SMTP integration and click the button to create an API key. The configuration is as follows:
```
mailer:
engine: smtp
smtp:
server: smtp.sendgrid.net
port: 587
encryption: tls
user: 'apikey'
password: 'YOUR_SENDGRID_API_KEY'
```
#### Mailgun
[Mailgun is a great service](https://www.mailgun.com/) that offers 10k/emails per month for free. Setup does require SPIF domain verification so that means you need to add at least a TXT entry in your DNS. This is pretty standard for SMTP sending services and does provide verification for remote email servers and makes your email sending more reliable. The Mailgun site, walks you through this process however, and the verification process is simple and fast.
```
mailer:
engine: smtp
smtp:
server: smtp.mailgun.org
port: 587
encryption: tls
user: 'MAILGUN_EMAIL_ADDRESS'
password: 'MAILGUN_EMAIL_PASSWORD'
```
Adjust these configurations for your account.
#### MailJet
Mailjet is another great service that is easy to quickly setup and get started sending email. The free account gives you 200 emails/day or 600 emails/month. Just signup and setup your SPF and DKIM entries for your domain. Then click on the SMTP settings and use those to configure the email plugin:
```
mailer:
engine: smtp
smtp:
server: in-v3.mailjet.com
port: 587
encryption: tls
user: 'MAILJUST_USERNAME_API_KEY'
password: 'MAILJUST_PASSWORD_SECRET_KEY'
```
It's that easy!
#### Sendmail
Although not as reliable as SMTP not providing as much debug information, sendmail is a simple option as long as your hosting provider is not blocking the default SMTP port `25`:
```
mailer:
engine: sendmail
sendmail:
bin: '/usr/sbin/sendmail -bs'
```
Simply adjust your binary command line to suite your environment
### SMTP Email Services
Solid SMTP options that even provide a FREE tier for low email volumes include:
* SendGrid (100/day free) - https://sendgrid.com
* Mailgun - (10k/month free) - https://www.mailgun.com
* Mailjet - (6k/month free) - https://www.mailjet.com/
* Sparkpost - (15k/month free) - https://www.sparkpost.com
* Amazon SES (62k/month free) - https://aws.amazon.com/ses/
If you are still unsure why should be using one in the first place, check out this article: https://zapier.com/learn/email-marketing/best-transactional-email-sending-services/
## Testing with CLI Command
You can test your email configuration with the following CLI Command:
```
$ bin/plugin email test-email -t steve@apple.com
```
You can also pass in a configuration environment:
```
$ bin/plugin email test-email -t steve@apple.com -e mysite.com
```
This will use the email configuration you have located in `user/mysite.com/config/plugins/email.yaml`. Read the docs to find out more about environment-based configuration: https://learn.getgrav.org/advanced/environment-config
# Programmatically send emails
Add this code in your plugins:
```php
$to = 'email@test.com';
$from = 'email@test.com';
$subject = 'Test';
$content = 'Test';
$message = $this->grav['Email']->message($subject, $content, 'text/html')
->setFrom($from)
->setTo($to);
$sent = $this->grav['Email']->send($message);
```
# Emails sent with Forms
When executing email actions during form processing, action parameters are inherited from the global configuration but may also be overridden on a per-action basis.
```
title: Custom form
form:
name: custom_form
fields:
# Any fields you'd like to add to the form:
# Their values may be referenced in email actions via '{{ form.value.FIELDNAME|e }}'
process:
- email:
subject: "[Custom form] {{ form.value.name|e }}"
body: "{% include 'forms/data.txt.twig' %}"
from: sender@example.com
from_name: 'Custom sender name'
to: recipient@example.com
to_name: 'Custom recipient name'
content_type: 'text/plain'
process_markdown: true
```
## Sending Attachments
You can add file inputs to your form, and send those files via Email.
Just add an `attachments` field and list the file input fields names. You can have multiple file fields, and this will send all the files as attachments. Example:
```
form:
name: custom_form
fields:
-
name: my-file
label: 'Add a file'
type: file
multiple: false
destination: user/data/files
accept:
- application/pdf
- application/x-pdf
- image/png
- text/plain
process:
-
email:
body: '{% include "forms/data.html.twig" %}'
attachments:
- 'my-file'
```
## Additional action parameters
To have more control over your generated email, you may also use the following additional parameters:
* `reply_to`: Set one or more addresses that should be used to reply to the message.
* `cc` _(Carbon copy)_: Add one or more addresses to the delivery list. Many email clients will mark email in one's inbox differently depending on whether they are in the `To:` or `Cc:` list.
* `bcc` _(Blind carbon copy)_: Add one or more addresses to the delivery list that should (usually) not be listed in the message data, remaining invisible to other recipients.
* `charset`: Explicitly set a charset for the generated email body (only takes effect if `body` parameter is a string, defaults to `utf-8`)
### Specifying email addresses
Email-related parameters (`from`, `to`, `reply_to`, `cc`and `bcc`) allow different notations for single / multiple values:
#### Single email address string
```
to: mail@example.com
```
#### Multiple email address strings
```
to:
- mail@example.com
- mail+1@example.com
- mail+2@example.com
```
#### Single email address with name
```
to:
mail: mail@example.com
name: Human-readable name
```
#### Multiple email addresses (with and without names)
```
to:
-
mail: mail@example.com
name: Human-readable name
-
mail: mail+2@example.com
name: Another human-readable name
-
mail+3@example.com
-
mail+4@example.com
```
## Multi-part MIME messages
Apart from a simple string, an email body may contain different MIME parts (e.g. HTML body with plain text fallback). You may even specify a different charset for each part (default to `utf-8`):
```
body:
-
content_type: 'text/html'
body: "{% include 'forms/default/data.html.twig' %}"
-
content_type: 'text/plain'
body: "{% include 'forms/default/data.txt.twig' %}"
charset: 'iso-8859-1'
```
# Troubleshooting
## Emails are not sent
#### Debugging
The first step in determining why emails are not sent is to enable debugging. This can be done via the `user/config/email.yaml` file or via the plugin settings in the admin. Just enable this and then try sending an email again. Then inspect the `logs/email.log` file for potential problems.
#### ISP Port 25 blocking
By default, when sending via PHP or Sendmail the machine running the webserver will attempt to send mail using the SMTP protocol. This uses port `25` which is often blocked by ISPs to protected against spamming. You can determine if this port is blocked by running this command in your temrinal (mac/linux only):
```
(echo >/dev/tcp/localhost/25) &>/dev/null && echo "TCP port 25 opened" || echo "TCP port 25 closed"
```
If it's blocked there are ways to configure relays to different ports, but the simplest solution is to use SMTP for mail sending.
#### Exceptions
If you get an exception when sending email but you cannot see what the error is, you need to enable more verbose exception messages. In the `user/config/system.yaml` file ensure your have the following configuration:
```
errors:
display: 1
log: true
```
## Configuration Issues
As explained above in the Configuration section, if you're using the default settings, set the Plugin configuration to use a SMTP server. It can be [Gmail](https://www.digitalocean.com/community/tutorials/how-to-use-google-s-smtp-server) or another SMTP server you have at your disposal.
This is the first thing to check. The reason is that PHP Mail, the default system used by the Plugin, is not 100% reliable and emails might not arrive.
+181
View File
@@ -0,0 +1,181 @@
name: Email
version: 2.7.1
description: Enables the emailing system for Grav
icon: envelope
author:
name: Team Grav
email: devs@getgrav.org
url: http://getgrav.org
keywords: plugin, email, sender
homepage: https://github.com/getgrav/grav-plugin-email
bugs: https://github.com/getgrav/grav-plugin-email/issues
license: MIT
dependencies:
- { name: grav, version: '>=1.1.9' }
form:
validation: loose
fields:
enabled:
type: hidden
label: PLUGIN_ADMIN.PLUGIN_STATUS
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
mailer.engine:
type: select
label: Mail Engine
size: medium
options:
none: Disabled
smtp: SMTP
sendmail: Sendmail
content_type:
type: select
label: Content type
size: medium
default: 'text/html'
options:
'text/plain': Plain text
'text/html': HTML
charset:
type: text
size: medium
label: Charset
placeholder: "Defaults to UTF-8"
from:
type: email
size: medium
label: Email from
placeholder: "Default email from address"
validate:
required: true
type: email
from_name:
type: text
size: medium
label: Email from name
placeholder: "Default email from name"
to:
type: email
size: medium
label: Email to
placeholder: "Default email to address"
multiple: true
validate:
required: true
type: email
to_name:
type: text
size: medium
label: Email to name
placeholder: "Default email to name"
cc:
type: email
size: medium
label: Email CC
placeholder: "Default email CC address"
multiple: true
validate:
type: email
cc_name:
type: text
size: medium
label: Email CC name
placeholder: "Default email CC name"
bcc:
type: email
size: medium
label: Email BCC
placeholder: "Default email BCC address"
multiple: true
validate:
type: email
reply_to:
type: email
size: medium
label: Email reply-to
placeholder: "Default email reply-to address"
multiple: true
validate:
type: email
reply_to_name:
type: text
size: medium
label: Email reply-to name
placeholder: "Default email reply-to name"
body:
type: textarea
size: medium
label: Email body
placeholder: "Defaults to a table of all form fields"
mailer.smtp.server:
type: text
size: medium
label: SMTP server
placeholder: "e.g. smtp.google.com"
mailer.smtp.port:
type: text
size: small
label: SMTP port
placeholder: "Defaults to 25 (plaintext) / 587 (encrypted)"
validate:
type: number
min: 1
max: 65535
mailer.smtp.encryption:
type: select
size: medium
label: SMTP encryption
options:
none: None
ssl: SSL
tls: TLS
mailer.smtp.user:
type: text
size: medium
label: SMTP login name
mailer.smtp.password:
type: password
size: medium
label: SMTP password
mailer.sendmail.bin:
type: text
size: medium
label: Path to sendmail
placeholder: "/usr/sbin/sendmail"
debug:
type: toggle
label: Debug
highlight: 1
default: 0
options:
true: PLUGIN_ADMIN.ENABLED
false: PLUGIN_ADMIN.DISABLED
validate:
type: bool
+191
View File
@@ -0,0 +1,191 @@
<?php
namespace Grav\Plugin\Email;
use Grav\Common\Config\Config;
use Grav\Common\Grav;
use \Monolog\Logger;
use \Monolog\Handler\StreamHandler;
class Email
{
/**
* @var \Swift_Transport
*/
protected $mailer;
/**
* @var \Swift_Plugins_LoggerPlugin
*/
protected $logger;
/**
* Returns true if emails have been enabled in the system.
*
* @return bool
*/
public function enabled()
{
return Grav::instance()['config']->get('plugins.email.mailer.engine') != 'none';
}
/**
* Returns true if debugging on emails has been enabled.
*
* @return bool
*/
public function debug()
{
return Grav::instance()['config']->get('plugins.email.debug') == 'true';
}
/**
* Creates an email message.
*
* @param string $subject
* @param string $body
* @param string $contentType
* @param string $charset
* @return \Swift_Message
*/
public function message($subject = null, $body = null, $contentType = null, $charset = null)
{
return new \Swift_Message($subject, $body, $contentType, $charset);
}
/**
* Creates an attachment.
*
* @param string $data
* @param string $filename
* @param string $contentType
* @return \Swift_Attachment
*/
public function attachment($data = null, $filename = null, $contentType = null)
{
return new \Swift_Attachment($data, $filename, $contentType);
}
/**
* Creates an embedded attachment.
*
* @param string $data
* @param string $filename
* @param string $contentType
* @return \Swift_EmbeddedFile
*/
public function embedded($data = null, $filename = null, $contentType = null)
{
return new \Swift_EmbeddedFile($data, $filename, $contentType);
}
/**
* Creates an image attachment.
*
* @param string $data
* @param string $filename
* @param string $contentType
* @return \Swift_Image
*/
public function image($data = null, $filename = null, $contentType = null)
{
return new \Swift_Image($data, $filename, $contentType);
}
/**
* Send email.
*
* @param \Swift_Message $message
* @return int
*/
public function send($message)
{
$mailer = $this->getMailer();
$result = $mailer ? $mailer->send($message) : 0;
// Check if emails and debugging are both enabled.
if ($mailer && $this->debug()) {
$log = new Logger('email');
$locator = Grav::instance()['locator'];
$log_file = $locator->findResource('log://email.log', true, true);
$log->pushHandler(new StreamHandler($log_file, Logger::DEBUG));
// Append the SwiftMailer log to the log.
$log->addDebug($this->getLogs());
}
return $result;
}
/**
* Return debugging logs if enabled
*
* @return string
*/
public function getLogs()
{
if ($this->debug()) {
return $this->logger->dump();
}
return '';
}
/**
* @internal
* @return null|\Swift_Mailer
*/
protected function getMailer()
{
if (!$this->enabled()) {
return null;
}
if (!$this->mailer) {
/** @var Config $config */
$config = Grav::instance()['config'];
$mailer = $config->get('plugins.email.mailer.engine');
// Create the Transport and initialize it.
switch ($mailer) {
case 'smtp':
$transport = \Swift_SmtpTransport::newInstance();
$options = $config->get('plugins.email.mailer.smtp');
if (!empty($options['server'])) {
$transport->setHost($options['server']);
}
if (!empty($options['port'])) {
$transport->setPort($options['port']);
}
if (!empty($options['encryption']) && $options['encryption'] != 'none') {
$transport->setEncryption($options['encryption']);
}
if (!empty($options['user'])) {
$transport->setUsername($options['user']);
}
if (!empty($options['password'])) {
$transport->setPassword($options['password']);
}
break;
case 'sendmail':
default:
$options = $config->get('plugins.email.mailer.sendmail');
$bin = !empty($options['bin']) ? $options['bin'] : '/usr/sbin/sendmail';
$transport = \Swift_SendmailTransport::newInstance($bin);
break;
}
// Create the Mailer using your created Transport
$this->mailer = \Swift_Mailer::newInstance($transport);
// Register the logger if we're debugging.
if ($this->debug()) {
$this->logger = new \Swift_Plugins_Loggers_ArrayLogger();
$this->mailer->registerPlugin(new \Swift_Plugins_LoggerPlugin($this->logger));
}
}
return $this->mailer;
}
}
+57
View File
@@ -0,0 +1,57 @@
<?php
namespace Grav\Plugin\Email;
use Grav\Common\Grav;
/**
* Class Utils
* @package Grav\Plugin\Email
*/
class Utils
{
/**
* Quick utility method to send an HTML email.
*
* @param $subject
* @param string $content
* @param string $to
* @param null $from
* @param string $mimetype
*
* @return bool True if the action was performed.
*/
public static function sendEmail($subject, $content, $to, $from = null, $mimetype = 'text/html')
{
$grav = Grav::instance();
if (!$from) {
$from = $grav['config']->get('plugins.email.from');
}
if (!isset($grav['Email']) || empty($from)) {
throw new \RuntimeException($grav['language']->translate('PLUGIN_EMAIL.PLEASE_CONFIGURE_A_FROM_ADDRESS'));
}
if (empty($to) || empty($subject) || empty($content)) {
return false;
}
//Initialize twig if not yet initialized
$grav['twig']->init();
$body = $grav['twig']->processTemplate('email/base.html.twig', ['content' => $content]);
$message = $grav['Email']->message($subject, $body, $mimetype)
->setFrom($from)
->setTo($to);
$sent = $grav['Email']->send($message);
if ($sent < 1) {
return false;
} else {
return true;
}
}
}
@@ -0,0 +1,98 @@
<?php
namespace Grav\Plugin\Console;
use Grav\Common\Grav;
use Grav\Console\ConsoleCommand;
use Grav\Plugin\Email\Email;
use Grav\Plugin\Email\Utils as EmailUtils;
use Symfony\Component\Console\Input\InputOption;
/**
* Class TestEmailCommand
* @package Grav\Console\Cli\
*/
class TestEmailCommand extends ConsoleCommand
{
/**
* @var array
*/
protected $options = [];
/**
*
*/
protected function configure()
{
$this
->setName('test-email')
->setAliases(['testemail'])
->addOption(
'to',
't',
InputOption::VALUE_REQUIRED,
'An email address to send the email to'
)
->addOption(
'env',
'e',
InputOption::VALUE_OPTIONAL,
'The environment to trigger a specific configuration. For example: localhost, mysite.dev, www.mysite.com'
)
->addOption(
'subject',
's',
InputOption::VALUE_OPTIONAL,
'A subject for the email'
)
->addOption(
'body',
'b',
InputOption::VALUE_OPTIONAL,
'The body of the email'
)
->setDescription('Sends a test email using the plugin\'s configuration')
->setHelp('The <info>test-email</info> command sends a test email using the plugin\'s configuration');
}
/**
* @return int|null|void
*/
protected function serve()
{
$grav = Grav::instance();
$this->output->writeln('');
$this->output->writeln('<yellow>Current Configuration:</yellow>');
$this->output->writeln('');
dump($grav['config']->get('plugins.email'));
$this->output->writeln('');
require_once __DIR__ . '/../vendor/autoload.php';
$grav['Email'] = new Email();
$email_to = $this->input->getOption('to') ?: $grav['config']->get('plugins.email.to');
$subject = $this->input->getOption('subject');
$body = $this->input->getOption('body');
if (!$subject) {
$subject = 'Testing Grav Email Plugin';
}
if (!$body) {
$configuration = print_r($grav['config']->get('plugins.email'), true);
$body = $grav['language']->translate(['PLUGIN_EMAIL.TEST_EMAIL_BODY', $configuration]);
}
$sent = EmailUtils::sendEmail($subject, $body, $email_to);
if ($sent) {
$this->output->writeln("<green>Message sent successfully!</green>");
} else {
$this->output->writeln("<red>Problem sending email...</red>");
}
}
}
+10
View File
@@ -0,0 +1,10 @@
{
"require": {
"swiftmailer/swiftmailer": "~5.4"
},
"autoload": {
"psr-4": {
"Grav\\Plugin\\Email\\": "classes/"
}
}
}
+72
View File
@@ -0,0 +1,72 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "2244976b3750b669fab6abb506e9c591",
"packages": [
{
"name": "swiftmailer/swiftmailer",
"version": "v5.4.8",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "9a06dc570a0367850280eefd3f1dc2da45aef517"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/9a06dc570a0367850280eefd3f1dc2da45aef517",
"reference": "9a06dc570a0367850280eefd3f1dc2da45aef517",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"mockery/mockery": "~0.9.1",
"symfony/phpunit-bridge": "~3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.4-dev"
}
},
"autoload": {
"files": [
"lib/swift_required.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Chris Corbyn"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Swiftmailer, free feature-rich PHP mailer",
"homepage": "http://swiftmailer.org",
"keywords": [
"email",
"mail",
"mailer"
],
"time": "2017-05-01T15:54:03+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": []
}
+323
View File
@@ -0,0 +1,323 @@
<?php
namespace Grav\Plugin;
use Grav\Common\Grav;
use Grav\Common\Plugin;
use Grav\Common\Twig\Twig;
use Grav\Plugin\Email\Email;
use RocketTheme\Toolbox\Event\Event;
use Swift_RfcComplianceException;
class EmailPlugin extends Plugin
{
/**
* @var Email
*/
protected $email;
/**
* @return array
*/
public static function getSubscribedEvents()
{
return [
'onPluginsInitialized' => ['onPluginsInitialized', 0],
'onFormProcessed' => ['onFormProcessed', 0],
'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0]
];
}
/**
* Initialize emailing.
*/
public function onPluginsInitialized()
{
require_once __DIR__ . '/vendor/autoload.php';
$this->email = new Email();
if ($this->email->enabled()) {
$this->grav['Email'] = $this->email;
}
}
/**
* Add twig paths to plugin templates.
*/
public function onTwigTemplatePaths()
{
$twig = $this->grav['twig'];
$twig->twig_paths[] = __DIR__ . '/templates';
}
/**
* Send email when processing the form data.
*
* @param Event $event
*/
public function onFormProcessed(Event $event)
{
$form = $event['form'];
$action = $event['action'];
$params = $event['params'];
if (!$this->email->enabled()) {
return;
}
switch ($action) {
case 'email':
// Prepare Twig variables
$vars = array(
'form' => $form
);
$grav = Grav::instance();
$grav->fireEvent('onEmailSend', new Event(['params' => &$params, 'vars' => &$vars]));
// Build message
$message = $this->buildMessage($params, $vars);
if (isset($params['attachments'])) {
$filesToAttach = (array)$params['attachments'];
if ($filesToAttach) foreach ($filesToAttach as $fileToAttach) {
$filesValues = $form->value($fileToAttach);
if ($filesValues) foreach($filesValues as $fileValues) {
if (isset($fileValues['file'])) {
$filename = $fileValues['file'];
} else {
$filename = ROOT_DIR . $fileValues['path'];
}
$message->attach(\Swift_Attachment::fromPath($filename));
}
}
}
// Send e-mail
$this->email->send($message);
break;
}
}
/**
* Build e-mail message.
*
* @param array $params
* @param array $vars
* @return \Swift_Message
*/
protected function buildMessage(array $params, array $vars = array())
{
/** @var Twig $twig */
$twig = $this->grav['twig'];
// Extend parameters with defaults.
$params += array(
'bcc' => $this->config->get('plugins.email.bcc', array()),
'body' => $this->config->get('plugins.email.body', '{% include "forms/data.html.twig" %}'),
'cc' => $this->config->get('plugins.email.cc', array()),
'cc_name' => $this->config->get('plugins.email.cc_name'),
'charset' => $this->config->get('plugins.email.charset', 'utf-8'),
'from' => $this->config->get('plugins.email.from'),
'from_name' => $this->config->get('plugins.email.from_name'),
'content_type' => $this->config->get('plugins.email.content_type', 'text/html'),
'reply_to' => $this->config->get('plugins.email.reply_to', array()),
'reply_to_name' => $this->config->get('plugins.email.reply_to_name'),
'subject' => !empty($vars['form']) && $vars['form'] instanceof Form ? $vars['form']->page()->title() : null,
'to' => $this->config->get('plugins.email.to'),
'to_name' => $this->config->get('plugins.email.to_name'),
'process_markdown' => false,
);
// Create message object.
$message = $this->email->message();
if (!$params['to']) {
throw new \RuntimeException($this->grav['language']->translate('PLUGIN_EMAIL.PLEASE_CONFIGURE_A_TO_ADDRESS'));
}
if (!$params['from']) {
throw new \RuntimeException($this->grav['language']->translate('PLUGIN_EMAIL.PLEASE_CONFIGURE_A_FROM_ADDRESS'));
}
// Process parameters.
foreach ($params as $key => $value) {
switch ($key) {
case 'bcc':
foreach ($this->parseAddressValue($value, $vars) as $address) {
try {
$message->addBcc($address->mail, $address->name);
} catch (Swift_RfcComplianceException $e) {
continue;
}
}
break;
case 'body':
if (is_string($value)) {
$body = $twig->processString($value, $vars);
if ($params['process_markdown']) {
$parsedown = new \Parsedown();
$body = $parsedown->text($body);
}
$content_type = !empty($params['content_type']) ? $twig->processString($params['content_type'], $vars) : null;
$charset = !empty($params['charset']) ? $twig->processString($params['charset'], $vars) : null;
$message->setBody($body, $content_type, $charset);
}
elseif (is_array($value)) {
foreach ($value as $body_part) {
$body_part += array(
'charset' => $params['charset'],
'content_type' => $params['content_type'],
);
$body = !empty($body_part['body']) ? $twig->processString($body_part['body'], $vars) : null;
if ($params['process_markdown']) {
$parsedown = new \Parsedown();
$body = $parsedown->text($body);
}
$content_type = !empty($body_part['content_type']) ? $twig->processString($body_part['content_type'], $vars) : null;
$charset = !empty($body_part['charset']) ? $twig->processString($body_part['charset'], $vars) : null;
if (!$message->getBody()) {
$message->setBody($body, $content_type, $charset);
}
else {
$message->addPart($body, $content_type, $charset);
}
}
}
break;
case 'cc':
if (is_string($value) && !empty($params['cc_name'])) {
$value = array(
'mail' => $twig->processString($value, $vars),
'name' => $twig->processString($params['cc_name'], $vars),
);
}
foreach ($this->parseAddressValue($value, $vars) as $address) {
try {
$message->addCc($address->mail, $address->name);
} catch (Swift_RfcComplianceException $e) {
continue;
}
}
break;
case 'from':
if (is_string($value) && !empty($params['from_name'])) {
$value = array(
'mail' => $twig->processString($value, $vars),
'name' => $twig->processString($params['from_name'], $vars),
);
}
foreach ($this->parseAddressValue($value, $vars) as $address) {
try {
$message->addFrom($address->mail, $address->name);
} catch (Swift_RfcComplianceException $e) {
continue;
}
}
break;
case 'reply_to':
if (is_string($value) && !empty($params['reply_to_name'])) {
$value = array(
'mail' => $twig->processString($value, $vars),
'name' => $twig->processString($params['reply_to_name'], $vars),
);
}
foreach ($this->parseAddressValue($value, $vars) as $address) {
try {
$message->addReplyTo($address->mail, $address->name);
} catch (Swift_RfcComplianceException $e) {
continue;
}
}
break;
case 'subject':
$message->setSubject($twig->processString($this->grav['language']->translate($value), $vars));
break;
case 'to':
if (is_string($value) && !empty($params['to_name'])) {
$value = array(
'mail' => $twig->processString($value, $vars),
'name' => $twig->processString($params['to_name'], $vars),
);
}
foreach ($this->parseAddressValue($value, $vars) as $address) {
try {
$message->addTo($address->mail, $address->name);
} catch (Swift_RfcComplianceException $e) {
continue;
}
}
break;
}
}
return $message;
}
/**
* Return parsed e-mail address value.
*
* @param $value
* @param array $vars
* @return array
*/
protected function parseAddressValue($value, array $vars = array())
{
$parsed = array();
/** @var Twig $twig */
$twig = $this->grav['twig'];
// Single e-mail address string
if (is_string($value)) {
$parsed[] = (object) array(
'mail' => $twig->processString($value, $vars),
'name' => null,
);
}
else {
// Cast value as array
$value = (array) $value;
// Single e-mail address array
if (!empty($value['mail'])) {
$parsed[] = (object) array(
'mail' => $twig->processString($value['mail'], $vars),
'name' => !empty($value['name']) ? $twig->processString($value['name'], $vars) : NULL,
);
}
// Multiple addresses (either as strings or arrays)
elseif (!(empty($value['mail']) && !empty($value['name']))) {
foreach ($value as $y => $itemx) {
$addresses = $this->parseAddressValue($itemx, $vars);
if (($address = reset($addresses))) {
$parsed[] = $address;
}
}
}
}
return $parsed;
}
}
+17
View File
@@ -0,0 +1,17 @@
enabled: true
from:
from_name:
to:
to_name:
mailer:
engine: sendmail
smtp:
server: localhost
port: 25
encryption: none
user: ''
password: ''
sendmail:
bin: '/usr/sbin/sendmail -bs'
content_type: text/html
debug: false
+56
View File
@@ -0,0 +1,56 @@
en:
PLUGIN_EMAIL:
EMAIL_NOT_CONFIGURED: "Email not configured"
PLEASE_CONFIGURE_A_TO_ADDRESS: "Please configure a 'to' address in the Email Plugin settings, or in the form"
PLEASE_CONFIGURE_A_FROM_ADDRESS: "Please configure a 'from' address in the Email Plugin settings, or in the form"
TEST_EMAIL_BODY: "<h1>Testing Email</h1><p>This test email has been sent based on the following configuration:</p> <p><pre>%1$s</pre></p>"
EMAIL_FOOTER: "GetGrav.org"
da:
PLUGIN_EMAIL:
PLEASE_CONFIGURE_A_TO_ADDRESS: "Konfigurere venligst en 'til' email adresse i Email Plugin indstillingerne eller her i formularen"
PLEASE_CONFIGURE_A_FROM_ADDRESS: "Konfigurere venligst en 'fra' email adresse i Email Plugin indstillingerne eller her i formularen"
de:
PLUGIN_EMAIL:
EMAIL_NOT_CONFIGURED: "E-Mail ist nicht konfiguriert"
PLEASE_CONFIGURE_A_TO_ADDRESS: "Bitte konfigurieren sie eine 'An' ('to') Adresse in den Email-Plugin-Einstellungen oder im Formular."
PLEASE_CONFIGURE_A_FROM_ADDRESS: "Bitte konfigurieren sie eine 'Von' ('from') Adresse in den Email-Plugin-Einstellungen oder im Formular."
es:
PLUGIN_EMAIL:
PLEASE_CONFIGURE_A_TO_ADDRESS: "Por favor configura una dirección de 'remitente' en la configuración del Plugin de Email o en el formulario"
PLEASE_CONFIGURE_A_FROM_ADDRESS: "Por favor configura una dirección de 'destinatario' en la configuración del Plugin de Email o en el formulario"
fr:
PLUGIN_EMAIL:
EMAIL_NOT_CONFIGURED: "Le-mail nest pas configuré"
PLEASE_CONFIGURE_A_TO_ADDRESS: "Veuillez configurer une adresse de 'destinataire' dans les paramètres du Plugin ou dans le formulaire."
PLEASE_CONFIGURE_A_FROM_ADDRESS: "Veuillez configurer une adresse 'd'expéditeur' dans les paramètres du Plugin ou dans le formulaire."
TEST_EMAIL_BODY: "<h1>E-mail de test</h1><p>Cet e-mail de test est basé sur la configuration suivante :</p> <p><pre>%1$s</pre></p>"
EMAIL_FOOTER: "GetGrav.org"
hr:
PLUGIN_EMAIL:
EMAIL_NOT_CONFIGURED: "Email nije konfiguriran"
PLEASE_CONFIGURE_A_TO_ADDRESS: "Konfigurirajte 'za' ('to') adresu u postavkama Email dodatka ili u obrascu"
PLEASE_CONFIGURE_A_FROM_ADDRESS: "Konfigurirajte 'od' ('from') adresu u postavkama Email dodatka ili u obrascu"
it:
PLUGIN_EMAIL:
PLEASE_CONFIGURE_A_TO_ADDRESS: "Per favore, configura l'indirizzo di destinazione ('to') nella configurazione del Plugin Email, oppure direttamente nella form."
PLEASE_CONFIGURE_A_FROM_ADDRESS: "Per favore, configura l'indirizzo di provenienza ('from') nella configurazione del Plugin Email, oppure direttamente nella form"
ro:
PLUGIN_EMAIL:
EMAIL_NOT_CONFIGURED: "Adresa de email nu este configurată"
PLEASE_CONFIGURE_A_TO_ADDRESS: "Vă rugam setați o adresă 'către' în setările modulului Email sau în formular"
PLEASE_CONFIGURE_A_FROM_ADDRESS: "Vă rugam setați o adresă 'de la' în setările modulului Email sau în formular"
ru:
PLUGIN_EMAIL:
EMAIL_NOT_CONFIGURED: "Электронная почта не настроена"
PLEASE_CONFIGURE_A_TO_ADDRESS: "Пожалуйста настройте адрес получателя ('to') в настройках плагина Email Plugin, или на форме"
PLEASE_CONFIGURE_A_FROM_ADDRESS: "Пожалуйста настройте адрес отправителя ('from') в настройках плагина Email Plugin, или на форме"
TEST_EMAIL_BODY: "<h1>Тестирование электронной почты</h1><p>Это тестовое письмо отправлено на основе следующей конфигурации:</p> <p><pre>%1$s</pre></p>"
EMAIL_FOOTER: "GetGrav.org"
@@ -0,0 +1,210 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title></title>
<style>
/* -------------------------------------
GLOBAL
------------------------------------- */
* {
margin: 0;
padding: 0;
font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;
font-size: 100%;
line-height: 1.6;
}
img {
max-width: 100%;
}
body {
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: none;
width: 100%!important;
height: 100%;
}
/* -------------------------------------
ELEMENTS
------------------------------------- */
a {
color: #348eda;
}
.btn-primary {
text-decoration: none;
color: #FFF;
background-color: #348eda;
border: solid #348eda;
border-width: 10px 20px;
line-height: 2;
font-weight: bold;
margin-right: 10px;
text-align: center;
cursor: pointer;
display: inline-block;
border-radius: 25px;
}
.btn-secondary {
text-decoration: none;
color: #FFF;
background-color: #aaa;
border: solid #aaa;
border-width: 10px 20px;
line-height: 2;
font-weight: bold;
margin-right: 10px;
text-align: center;
cursor: pointer;
display: inline-block;
border-radius: 25px;
}
.last {
margin-bottom: 0;
}
.first {
margin-top: 0;
}
.padding {
padding: 10px 0;
}
/* -------------------------------------
BODY
------------------------------------- */
table.body-wrap {
width: 100%;
padding: 20px;
}
table.body-wrap .container {
border: 1px solid #f0f0f0;
}
/* -------------------------------------
FOOTER
------------------------------------- */
table.footer-wrap {
width: 100%;
clear: both!important;
}
.footer-wrap .container p {
font-size: 12px;
color: #666;
}
table.footer-wrap a {
color: #999;
}
/* -------------------------------------
TYPOGRAPHY
------------------------------------- */
h1, h2, h3 {
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
color: #000;
margin: 40px 0 10px;
line-height: 1.2;
font-weight: 200;
}
h1 {
font-size: 36px;
}
h2 {
font-size: 28px;
}
h3 {
font-size: 22px;
}
p, ul, ol {
margin-bottom: 10px;
font-weight: normal;
font-size: 14px;
}
ul li, ol li {
margin-left: 5px;
list-style-position: inside;
}
.word-break {
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
/* This is the dangerous one in WebKit, as it breaks things wherever */
word-break: break-all;
/* Instead use this non-standard one: */
word-break: break-word;
/* Adds a hyphen where the word breaks, if supported (No Blink) */
-ms-hyphens: auto;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
/* ---------------------------------------------------
RESPONSIVENESS
Nuke it from orbit. It's the only way to be sure.
------------------------------------------------------ */
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
.container {
display: block!important;
max-width: 600px!important;
margin: 0 auto!important; /* makes it centered */
clear: both!important;
}
/* Set the padding on the td rather than the div for Outlook compatibility */
.body-wrap .container {
padding: 20px;
}
/* This should also be a block element, so that it will fill 100% of the .container */
.content {
max-width: 600px;
margin: 0 auto;
display: block;
}
/* Let's make sure tables in the content area are 100% wide */
.content table {
width: 100%;
}
</style>
</head>
<body bgcolor="#f6f6f6">
<!-- body -->
<table class="body-wrap" bgcolor="#f6f6f6">
<tr>
<td></td>
<td class="container" bgcolor="#FFFFFF">
<div class="content">
<table>
<tr>
<td>
{{ content|raw }}
</td>
</tr>
</table>
</div>
</td>
<td></td>
</tr>
</table>
<!-- /body -->
<!-- footer -->
<table class="footer-wrap">
<tr>
<td></td>
<td class="container">
<div class="content">
<table>
<tr>
<td align="center">
{{ 'PLUGIN_EMAIL.EMAIL_FOOTER'|t }}
</td>
</tr>
</table>
</div>
</td>
<td></td>
</tr>
</table>
<!-- /footer -->
</body>
</html>
+7
View File
@@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitdec5d78def1384d1f20996ded9d7efbf::getLoader();
+445
View File
@@ -0,0 +1,445 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath.'\\';
if (isset($this->prefixDirsPsr4[$search])) {
foreach ($this->prefixDirsPsr4[$search] as $dir) {
$length = $this->prefixLengthsPsr4[$first][$search];
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}
+56
View File
@@ -0,0 +1,56 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: Composer
Upstream-Contact: Jordi Boggiano <j.boggiano@seld.be>
Source: https://github.com/composer/composer
Files: *
Copyright: 2016, Nils Adermann <naderman@naderman.de>
2016, Jordi Boggiano <j.boggiano@seld.be>
License: Expat
Files: src/Composer/Util/TlsHelper.php
Copyright: 2016, Nils Adermann <naderman@naderman.de>
2016, Jordi Boggiano <j.boggiano@seld.be>
2013, Evan Coury <me@evancoury.com>
License: Expat and BSD-2-Clause
License: BSD-2-Clause
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
.
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
License: Expat
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.
@@ -0,0 +1,9 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
+10
View File
@@ -0,0 +1,10 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php',
);
@@ -0,0 +1,9 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
+10
View File
@@ -0,0 +1,10 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Grav\\Plugin\\Email\\' => array($baseDir . '/classes'),
);
+70
View File
@@ -0,0 +1,70 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitdec5d78def1384d1f20996ded9d7efbf
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitdec5d78def1384d1f20996ded9d7efbf', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitdec5d78def1384d1f20996ded9d7efbf', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequiredec5d78def1384d1f20996ded9d7efbf($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequiredec5d78def1384d1f20996ded9d7efbf($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf
{
public static $files = array (
'2c102faa651ef8ea5874edb585946bce' => __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php',
);
public static $prefixLengthsPsr4 = array (
'G' =>
array (
'Grav\\Plugin\\Email\\' => 18,
),
);
public static $prefixDirsPsr4 = array (
'Grav\\Plugin\\Email\\' =>
array (
0 => __DIR__ . '/../..' . '/classes',
),
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitdec5d78def1384d1f20996ded9d7efbf::$prefixDirsPsr4;
}, null, ClassLoader::class);
}
}
+58
View File
@@ -0,0 +1,58 @@
[
{
"name": "swiftmailer/swiftmailer",
"version": "v5.4.8",
"version_normalized": "5.4.8.0",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "9a06dc570a0367850280eefd3f1dc2da45aef517"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/9a06dc570a0367850280eefd3f1dc2da45aef517",
"reference": "9a06dc570a0367850280eefd3f1dc2da45aef517",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"mockery/mockery": "~0.9.1",
"symfony/phpunit-bridge": "~3.2"
},
"time": "2017-05-01T15:54:03+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.4-dev"
}
},
"installation-source": "dist",
"autoload": {
"files": [
"lib/swift_required.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Chris Corbyn"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Swiftmailer, free feature-rich PHP mailer",
"homepage": "http://swiftmailer.org",
"keywords": [
"email",
"mail",
"mailer"
]
}
]
@@ -0,0 +1,267 @@
Changelog
=========
5.4.8 (2017-05-01)
------------------
* fixed encoding inheritance in addPart()
* fixed sorting MIME children when their types are equal
5.4.7 (2017-04-20)
------------------
* fixed NTLMAuthenticator clobbering bcmath scale
5.4.6 (2017-02-13)
------------------
* removed exceptions thrown in destructors as they lead to fatal errors
* switched to use sha256 by default in DKIM as per the RFC
* fixed an 'Undefined variable: pipes' PHP notice
* fixed long To headers when using the mail transport
* fixed NTLMAuthenticator when no domain is passed with the username
* prevented fatal error during unserialization of a message
* fixed a PHP warning when sending a message that has a length of a multiple of 8192
5.4.5 (2016-12-29)
------------------
* SECURITY FIX: fixed CVE-2016-10074 by disallowing potentially unsafe shell characters
Prior to 5.4.5, the mail transport (Swift_Transport_MailTransport) was vulnerable to passing
arbitrary shell arguments if the "From", "ReturnPath" or "Sender" header came
from a non-trusted source, potentially allowing Remote Code Execution
* deprecated the mail transport
5.4.4 (2016-11-23)
------------------
* reverted escaping command-line args to mail (PHP mail() function already does it)
5.4.3 (2016-07-08)
------------------
* fixed SimpleHeaderSet::has()/get() when the 0 index is removed
* removed the need to have mcrypt installed
* fixed broken MIME header encoding with quotes/colons and non-ascii chars
* allowed mail transport send for messages without To header
* fixed PHP 7 support
5.4.2 (2016-05-01)
------------------
* fixed support for IPv6 sockets
* added auto-retry when sending messages from the memory spool
* fixed consecutive read calls in Swift_ByteStream_FileByteStream
* added support for iso-8859-15 encoding
* fixed PHP mail extra params on missing reversePath
* added methods to set custom stream context options
* fixed charset changes in QpContentEncoderProxy
* added return-path header to the ignoredHeaders list of DKIMSigner
* fixed crlf for subject using mail
* fixed add soft line break only when necessary
* fixed escaping command-line args to mail
5.4.1 (2015-06-06)
------------------
* made Swiftmailer exceptions confirm to PHP base exception constructor signature
* fixed MAIL FROM & RCPT TO headers to be RFC compliant
5.4.0 (2015-03-14)
------------------
* added the possibility to add extra certs to PKCS#7 signature
* fix base64 encoding with streams
* added a new RESULT_SPOOLED status for SpoolTransport
* fixed getBody() on attachments when called more than once
* removed dots from generated filenames in filespool
5.3.1 (2014-12-05)
------------------
* fixed cloning of messages with attachments
5.3.0 (2014-10-04)
------------------
* fixed cloning when using signers
* reverted removal of Swift_Encoding
* drop support for PHP 5.2.x
5.2.2 (2014-09-20)
------------------
* fixed Japanese support
* fixed the memory spool when the message changes when in the pool
* added support for cloning messages
* fixed PHP warning in the redirect plugin
* changed the way to and cc-ed email are sent to only use one transaction
5.2.1 (2014-06-13)
------------------
* SECURITY FIX: fixed CLI escaping when using sendmail as a transport
Prior to 5.2.1, the sendmail transport (Swift_Transport_SendmailTransport)
was vulnerable to an arbitrary shell execution if the "From" header came
from a non-trusted source and no "Return-Path" is configured.
* fixed parameter in DKIMSigner
* fixed compatibility with PHP < 5.4
5.2.0 (2014-05-08)
------------------
* fixed Swift_ByteStream_FileByteStream::read() to match to the specification
* fixed from-charset and to-charset arguments in mbstring_convert_encoding() usages
* fixed infinite loop in StreamBuffer
* fixed NullTransport to return the number of ignored emails instead of 0
* Use phpunit and mockery for unit testing (realityking)
5.1.0 (2014-03-18)
------------------
* fixed data writing to stream when sending large messages
* added support for libopendkim (https://github.com/xdecock/php-opendkim)
* merged SignedMessage and Message
* added Gmail XOAuth2 authentication
* updated the list of known mime types
* added NTLM authentication
5.0.3 (2013-12-03)
------------------
* fixed double-dot bug
* fixed DKIM signer
5.0.2 (2013-08-30)
------------------
* handled correct exception type while reading IoBuffer output
5.0.1 (2013-06-17)
------------------
* changed the spool to only start the transport when a mail has to be sent
* fixed compatibility with PHP 5.2
* fixed LICENSE file
5.0.0 (2013-04-30)
------------------
* changed the license from LGPL to MIT
4.3.1 (2013-04-11)
------------------
* removed usage of the native QP encoder when the charset is not UTF-8
* fixed usage of uniqid to avoid collisions
* made a performance improvement when tokenizing large headers
* fixed usage of the PHP native QP encoder on PHP 5.4.7+
4.3.0 (2013-01-08)
------------------
* made the temporary directory configurable via the TMPDIR env variable
* added S/MIME signer and encryption support
4.2.2 (2012-10-25)
------------------
* added the possibility to throttle messages per second in ThrottlerPlugin (mostly for Amazon SES)
* switched mime.qpcontentencoder to automatically use the PHP native encoder on PHP 5.4.7+
* allowed specifying a whitelist with regular expressions in RedirectingPlugin
4.2.1 (2012-07-13)
------------------
* changed the coding standards to PSR-1/2
* fixed issue with autoloading
* added NativeQpContentEncoder to enhance performance (for PHP 5.3+)
4.2.0 (2012-06-29)
------------------
* added documentation about how to use the Japanese support introduced in 4.1.8
* added a way to override the default configuration in a lazy way
* changed the PEAR init script to lazy-load the initialization
* fixed a bug when calling Swift_Preferences before anything else (regression introduced in 4.1.8)
4.1.8 (2012-06-17)
------------------
* added Japanese iso-2022-jp support
* changed the init script to lazy-load the initialization
* fixed docblocks (@id) which caused some problems with libraries parsing the dobclocks
* fixed Swift_Mime_Headers_IdentificationHeader::setId() when passed an array of ids
* fixed encoding of email addresses in headers
* added replacements setter to the Decorator plugin
4.1.7 (2012-04-26)
------------------
* fixed QpEncoder safeMapShareId property
4.1.6 (2012-03-23)
------------------
* reduced the size of serialized Messages
4.1.5 (2012-01-04)
------------------
* enforced Swift_Spool::queueMessage() to return a Boolean
* made an optimization to the memory spool: start the transport only when required
* prevented stream_socket_client() from generating an error and throw a Swift_TransportException instead
* fixed a PHP warning when calling to mail() when safe_mode is off
* many doc tweaks
4.1.4 (2011-12-16)
------------------
* added a memory spool (Swift_MemorySpool)
* fixed too many opened files when sending emails with attachments
4.1.3 (2011-10-27)
------------------
* added STARTTLS support
* added missing @return tags on fluent methods
* added a MessageLogger plugin that logs all sent messages
* added composer.json
4.1.2 (2011-09-13)
------------------
* fixed wrong detection of magic_quotes_runtime
* fixed fatal errors when no To or Subject header has been set
* fixed charset on parameter header continuations
* added documentation about how to install Swiftmailer from the PEAR channel
* fixed various typos and markup problem in the documentation
* fixed warning when cache directory does not exist
* fixed "slashes are escaped" bug
* changed require_once() to require() in autoload
4.1.1 (2011-07-04)
------------------
* added missing file in PEAR package
4.1.0 (2011-06-30)
------------------
* documentation has been converted to ReST
4.1.0 RC1 (2011-06-17)
----------------------
New features:
* changed the Decorator Plugin to allow replacements in all headers
* added Swift_Mime_Grammar and Swift_Validate to validate an email address
* modified the autoloader to lazy-initialize Swiftmailer
* removed Swift_Mailer::batchSend()
* added NullTransport
* added new plugins: RedirectingPlugin and ImpersonatePlugin
* added a way to send messages asynchronously (Spool)
@@ -0,0 +1,19 @@
Copyright (c) 2013-2016 Fabien Potencier
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.
@@ -0,0 +1,15 @@
Swift Mailer
------------
Swift Mailer is a component based mailing solution for PHP 5.
It is released under the MIT license.
Homepage: http://swiftmailer.org
Documentation: http://swiftmailer.org/docs
Bugs: https://github.com/swiftmailer/swiftmailer/issues
Repository: https://github.com/swiftmailer/swiftmailer
Swift Mailer is highly object-oriented by design and lends itself
to use in complex web application with a great deal of flexibility.
For full details on usage, see the documentation.
@@ -0,0 +1 @@
Swift-5.4.8
@@ -0,0 +1,37 @@
{
"name": "swiftmailer/swiftmailer",
"type": "library",
"description": "Swiftmailer, free feature-rich PHP mailer",
"keywords": ["mail","mailer","email"],
"homepage": "http://swiftmailer.org",
"license": "MIT",
"authors": [
{
"name": "Chris Corbyn"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"mockery/mockery": "~0.9.1",
"symfony/phpunit-bridge": "~3.2"
},
"autoload": {
"files": ["lib/swift_required.php"]
},
"autoload-dev": {
"psr-0": {
"Swift_": "tests/unit"
}
},
"extra": {
"branch-alias": {
"dev-master": "5.4-dev"
}
}
}
@@ -0,0 +1,80 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* General utility class in Swift Mailer, not to be instantiated.
*
*
* @author Chris Corbyn
*/
abstract class Swift
{
/** Swift Mailer Version number generated during dist release process */
const VERSION = '@SWIFT_VERSION_NUMBER@';
public static $initialized = false;
public static $inits = array();
/**
* Registers an initializer callable that will be called the first time
* a SwiftMailer class is autoloaded.
*
* This enables you to tweak the default configuration in a lazy way.
*
* @param mixed $callable A valid PHP callable that will be called when autoloading the first Swift class
*/
public static function init($callable)
{
self::$inits[] = $callable;
}
/**
* Internal autoloader for spl_autoload_register().
*
* @param string $class
*/
public static function autoload($class)
{
// Don't interfere with other autoloaders
if (0 !== strpos($class, 'Swift_')) {
return;
}
$path = __DIR__.'/'.str_replace('_', '/', $class).'.php';
if (!file_exists($path)) {
return;
}
require $path;
if (self::$inits && !self::$initialized) {
self::$initialized = true;
foreach (self::$inits as $init) {
call_user_func($init);
}
}
}
/**
* Configure autoloading using Swift Mailer.
*
* This is designed to play nicely with other autoloaders.
*
* @param mixed $callable A valid PHP callable that will be called when autoloading the first Swift class
*/
public static function registerAutoload($callable = null)
{
if (null !== $callable) {
self::$inits[] = $callable;
}
spl_autoload_register(array('Swift', 'autoload'));
}
}
@@ -0,0 +1,71 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Attachment class for attaching files to a {@link Swift_Mime_Message}.
*
* @author Chris Corbyn
*/
class Swift_Attachment extends Swift_Mime_Attachment
{
/**
* Create a new Attachment.
*
* Details may be optionally provided to the constructor.
*
* @param string|Swift_OutputByteStream $data
* @param string $filename
* @param string $contentType
*/
public function __construct($data = null, $filename = null, $contentType = null)
{
call_user_func_array(
array($this, 'Swift_Mime_Attachment::__construct'),
Swift_DependencyContainer::getInstance()
->createDependenciesFor('mime.attachment')
);
$this->setBody($data);
$this->setFilename($filename);
if ($contentType) {
$this->setContentType($contentType);
}
}
/**
* Create a new Attachment.
*
* @param string|Swift_OutputByteStream $data
* @param string $filename
* @param string $contentType
*
* @return Swift_Mime_Attachment
*/
public static function newInstance($data = null, $filename = null, $contentType = null)
{
return new self($data, $filename, $contentType);
}
/**
* Create a new Attachment from a filesystem path.
*
* @param string $path
* @param string $contentType optional
*
* @return Swift_Mime_Attachment
*/
public static function fromPath($path, $contentType = null)
{
return self::newInstance()->setFile(
new Swift_ByteStream_FileByteStream($path),
$contentType
);
}
}
@@ -0,0 +1,181 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Provides the base functionality for an InputStream supporting filters.
*
* @author Chris Corbyn
*/
abstract class Swift_ByteStream_AbstractFilterableInputStream implements Swift_InputByteStream, Swift_Filterable
{
/**
* Write sequence.
*/
protected $_sequence = 0;
/**
* StreamFilters.
*
* @var Swift_StreamFilter[]
*/
private $_filters = array();
/**
* A buffer for writing.
*/
private $_writeBuffer = '';
/**
* Bound streams.
*
* @var Swift_InputByteStream[]
*/
private $_mirrors = array();
/**
* Commit the given bytes to the storage medium immediately.
*
* @param string $bytes
*/
abstract protected function _commit($bytes);
/**
* Flush any buffers/content with immediate effect.
*/
abstract protected function _flush();
/**
* Add a StreamFilter to this InputByteStream.
*
* @param Swift_StreamFilter $filter
* @param string $key
*/
public function addFilter(Swift_StreamFilter $filter, $key)
{
$this->_filters[$key] = $filter;
}
/**
* Remove an already present StreamFilter based on its $key.
*
* @param string $key
*/
public function removeFilter($key)
{
unset($this->_filters[$key]);
}
/**
* Writes $bytes to the end of the stream.
*
* @param string $bytes
*
* @throws Swift_IoException
*
* @return int
*/
public function write($bytes)
{
$this->_writeBuffer .= $bytes;
foreach ($this->_filters as $filter) {
if ($filter->shouldBuffer($this->_writeBuffer)) {
return;
}
}
$this->_doWrite($this->_writeBuffer);
return ++$this->_sequence;
}
/**
* For any bytes that are currently buffered inside the stream, force them
* off the buffer.
*
* @throws Swift_IoException
*/
public function commit()
{
$this->_doWrite($this->_writeBuffer);
}
/**
* Attach $is to this stream.
*
* The stream acts as an observer, receiving all data that is written.
* All {@link write()} and {@link flushBuffers()} operations will be mirrored.
*
* @param Swift_InputByteStream $is
*/
public function bind(Swift_InputByteStream $is)
{
$this->_mirrors[] = $is;
}
/**
* Remove an already bound stream.
*
* If $is is not bound, no errors will be raised.
* If the stream currently has any buffered data it will be written to $is
* before unbinding occurs.
*
* @param Swift_InputByteStream $is
*/
public function unbind(Swift_InputByteStream $is)
{
foreach ($this->_mirrors as $k => $stream) {
if ($is === $stream) {
if ($this->_writeBuffer !== '') {
$stream->write($this->_writeBuffer);
}
unset($this->_mirrors[$k]);
}
}
}
/**
* Flush the contents of the stream (empty it) and set the internal pointer
* to the beginning.
*
* @throws Swift_IoException
*/
public function flushBuffers()
{
if ($this->_writeBuffer !== '') {
$this->_doWrite($this->_writeBuffer);
}
$this->_flush();
foreach ($this->_mirrors as $stream) {
$stream->flushBuffers();
}
}
/** Run $bytes through all filters */
private function _filter($bytes)
{
foreach ($this->_filters as $filter) {
$bytes = $filter->filter($bytes);
}
return $bytes;
}
/** Just write the bytes to the stream */
private function _doWrite($bytes)
{
$this->_commit($this->_filter($bytes));
foreach ($this->_mirrors as $stream) {
$stream->write($bytes);
}
$this->_writeBuffer = '';
}
}
@@ -0,0 +1,182 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Allows reading and writing of bytes to and from an array.
*
* @author Chris Corbyn
*/
class Swift_ByteStream_ArrayByteStream implements Swift_InputByteStream, Swift_OutputByteStream
{
/**
* The internal stack of bytes.
*
* @var string[]
*/
private $_array = array();
/**
* The size of the stack.
*
* @var int
*/
private $_arraySize = 0;
/**
* The internal pointer offset.
*
* @var int
*/
private $_offset = 0;
/**
* Bound streams.
*
* @var Swift_InputByteStream[]
*/
private $_mirrors = array();
/**
* Create a new ArrayByteStream.
*
* If $stack is given the stream will be populated with the bytes it contains.
*
* @param mixed $stack of bytes in string or array form, optional
*/
public function __construct($stack = null)
{
if (is_array($stack)) {
$this->_array = $stack;
$this->_arraySize = count($stack);
} elseif (is_string($stack)) {
$this->write($stack);
} else {
$this->_array = array();
}
}
/**
* Reads $length bytes from the stream into a string and moves the pointer
* through the stream by $length.
*
* If less bytes exist than are requested the
* remaining bytes are given instead. If no bytes are remaining at all, boolean
* false is returned.
*
* @param int $length
*
* @return string
*/
public function read($length)
{
if ($this->_offset == $this->_arraySize) {
return false;
}
// Don't use array slice
$end = $length + $this->_offset;
$end = $this->_arraySize < $end ? $this->_arraySize : $end;
$ret = '';
for (; $this->_offset < $end; ++$this->_offset) {
$ret .= $this->_array[$this->_offset];
}
return $ret;
}
/**
* Writes $bytes to the end of the stream.
*
* @param string $bytes
*/
public function write($bytes)
{
$to_add = str_split($bytes);
foreach ($to_add as $value) {
$this->_array[] = $value;
}
$this->_arraySize = count($this->_array);
foreach ($this->_mirrors as $stream) {
$stream->write($bytes);
}
}
/**
* Not used.
*/
public function commit()
{
}
/**
* Attach $is to this stream.
*
* The stream acts as an observer, receiving all data that is written.
* All {@link write()} and {@link flushBuffers()} operations will be mirrored.
*
* @param Swift_InputByteStream $is
*/
public function bind(Swift_InputByteStream $is)
{
$this->_mirrors[] = $is;
}
/**
* Remove an already bound stream.
*
* If $is is not bound, no errors will be raised.
* If the stream currently has any buffered data it will be written to $is
* before unbinding occurs.
*
* @param Swift_InputByteStream $is
*/
public function unbind(Swift_InputByteStream $is)
{
foreach ($this->_mirrors as $k => $stream) {
if ($is === $stream) {
unset($this->_mirrors[$k]);
}
}
}
/**
* Move the internal read pointer to $byteOffset in the stream.
*
* @param int $byteOffset
*
* @return bool
*/
public function setReadPointer($byteOffset)
{
if ($byteOffset > $this->_arraySize) {
$byteOffset = $this->_arraySize;
} elseif ($byteOffset < 0) {
$byteOffset = 0;
}
$this->_offset = $byteOffset;
}
/**
* Flush the contents of the stream (empty it) and set the internal pointer
* to the beginning.
*/
public function flushBuffers()
{
$this->_offset = 0;
$this->_array = array();
$this->_arraySize = 0;
foreach ($this->_mirrors as $stream) {
$stream->flushBuffers();
}
}
}
@@ -0,0 +1,231 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Allows reading and writing of bytes to and from a file.
*
* @author Chris Corbyn
*/
class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream implements Swift_FileStream
{
/** The internal pointer offset */
private $_offset = 0;
/** The path to the file */
private $_path;
/** The mode this file is opened in for writing */
private $_mode;
/** A lazy-loaded resource handle for reading the file */
private $_reader;
/** A lazy-loaded resource handle for writing the file */
private $_writer;
/** If magic_quotes_runtime is on, this will be true */
private $_quotes = false;
/** If stream is seekable true/false, or null if not known */
private $_seekable = null;
/**
* Create a new FileByteStream for $path.
*
* @param string $path
* @param bool $writable if true
*/
public function __construct($path, $writable = false)
{
if (empty($path)) {
throw new Swift_IoException('The path cannot be empty');
}
$this->_path = $path;
$this->_mode = $writable ? 'w+b' : 'rb';
if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) {
$this->_quotes = true;
}
}
/**
* Get the complete path to the file.
*
* @return string
*/
public function getPath()
{
return $this->_path;
}
/**
* Reads $length bytes from the stream into a string and moves the pointer
* through the stream by $length.
*
* If less bytes exist than are requested the
* remaining bytes are given instead. If no bytes are remaining at all, boolean
* false is returned.
*
* @param int $length
*
* @throws Swift_IoException
*
* @return string|bool
*/
public function read($length)
{
$fp = $this->_getReadHandle();
if (!feof($fp)) {
if ($this->_quotes) {
ini_set('magic_quotes_runtime', 0);
}
$bytes = fread($fp, $length);
if ($this->_quotes) {
ini_set('magic_quotes_runtime', 1);
}
$this->_offset = ftell($fp);
// If we read one byte after reaching the end of the file
// feof() will return false and an empty string is returned
if ($bytes === '' && feof($fp)) {
$this->_resetReadHandle();
return false;
}
return $bytes;
}
$this->_resetReadHandle();
return false;
}
/**
* Move the internal read pointer to $byteOffset in the stream.
*
* @param int $byteOffset
*
* @return bool
*/
public function setReadPointer($byteOffset)
{
if (isset($this->_reader)) {
$this->_seekReadStreamToPosition($byteOffset);
}
$this->_offset = $byteOffset;
}
/** Just write the bytes to the file */
protected function _commit($bytes)
{
fwrite($this->_getWriteHandle(), $bytes);
$this->_resetReadHandle();
}
/** Not used */
protected function _flush()
{
}
/** Get the resource for reading */
private function _getReadHandle()
{
if (!isset($this->_reader)) {
$pointer = @fopen($this->_path, 'rb');
if (!$pointer) {
throw new Swift_IoException(
'Unable to open file for reading ['.$this->_path.']'
);
}
$this->_reader = $pointer;
if ($this->_offset != 0) {
$this->_getReadStreamSeekableStatus();
$this->_seekReadStreamToPosition($this->_offset);
}
}
return $this->_reader;
}
/** Get the resource for writing */
private function _getWriteHandle()
{
if (!isset($this->_writer)) {
if (!$this->_writer = fopen($this->_path, $this->_mode)) {
throw new Swift_IoException(
'Unable to open file for writing ['.$this->_path.']'
);
}
}
return $this->_writer;
}
/** Force a reload of the resource for reading */
private function _resetReadHandle()
{
if (isset($this->_reader)) {
fclose($this->_reader);
$this->_reader = null;
}
}
/** Check if ReadOnly Stream is seekable */
private function _getReadStreamSeekableStatus()
{
$metas = stream_get_meta_data($this->_reader);
$this->_seekable = $metas['seekable'];
}
/** Streams in a readOnly stream ensuring copy if needed */
private function _seekReadStreamToPosition($offset)
{
if ($this->_seekable === null) {
$this->_getReadStreamSeekableStatus();
}
if ($this->_seekable === false) {
$currentPos = ftell($this->_reader);
if ($currentPos < $offset) {
$toDiscard = $offset - $currentPos;
fread($this->_reader, $toDiscard);
return;
}
$this->_copyReadStream();
}
fseek($this->_reader, $offset, SEEK_SET);
}
/** Copy a readOnly Stream to ensure seekability */
private function _copyReadStream()
{
if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) {
/* We have opened a php:// Stream Should work without problem */
} elseif (function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) {
/* We have opened a tmpfile */
} else {
throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available');
}
$currentPos = ftell($this->_reader);
fclose($this->_reader);
$source = fopen($this->_path, 'rb');
if (!$source) {
throw new Swift_IoException('Unable to open file for copying ['.$this->_path.']');
}
fseek($tmpFile, 0, SEEK_SET);
while (!feof($source)) {
fwrite($tmpFile, fread($source, 4096));
}
fseek($tmpFile, $currentPos, SEEK_SET);
fclose($source);
$this->_reader = $tmpFile;
}
}
@@ -0,0 +1,42 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* @author Romain-Geissler
*/
class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream
{
public function __construct()
{
$filePath = tempnam(sys_get_temp_dir(), 'FileByteStream');
if ($filePath === false) {
throw new Swift_IoException('Failed to retrieve temporary file name.');
}
parent::__construct($filePath, true);
}
public function getContent()
{
if (($content = file_get_contents($this->getPath())) === false) {
throw new Swift_IoException('Failed to get temporary file content.');
}
return $content;
}
public function __destruct()
{
if (file_exists($this->getPath())) {
@unlink($this->getPath());
}
}
}
@@ -0,0 +1,67 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Analyzes characters for a specific character set.
*
* @author Chris Corbyn
* @author Xavier De Cock <xdecock@gmail.com>
*/
interface Swift_CharacterReader
{
const MAP_TYPE_INVALID = 0x01;
const MAP_TYPE_FIXED_LEN = 0x02;
const MAP_TYPE_POSITIONS = 0x03;
/**
* Returns the complete character map.
*
* @param string $string
* @param int $startOffset
* @param array $currentMap
* @param mixed $ignoredChars
*
* @return int
*/
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars);
/**
* Returns the mapType, see constants.
*
* @return int
*/
public function getMapType();
/**
* Returns an integer which specifies how many more bytes to read.
*
* A positive integer indicates the number of more bytes to fetch before invoking
* this method again.
*
* A value of zero means this is already a valid character.
* A value of -1 means this cannot possibly be a valid character.
*
* @param int[] $bytes
* @param int $size
*
* @return int
*/
public function validateByteSequence($bytes, $size);
/**
* Returns the number of bytes which should be read to start each character.
*
* For fixed width character sets this should be the number of octets-per-character.
* For multibyte character sets this will probably be 1.
*
* @return int
*/
public function getInitialByteSize();
}
@@ -0,0 +1,97 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Provides fixed-width byte sizes for reading fixed-width character sets.
*
* @author Chris Corbyn
* @author Xavier De Cock <xdecock@gmail.com>
*/
class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterReader
{
/**
* The number of bytes in a single character.
*
* @var int
*/
private $_width;
/**
* Creates a new GenericFixedWidthReader using $width bytes per character.
*
* @param int $width
*/
public function __construct($width)
{
$this->_width = $width;
}
/**
* Returns the complete character map.
*
* @param string $string
* @param int $startOffset
* @param array $currentMap
* @param mixed $ignoredChars
*
* @return int
*/
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
{
$strlen = strlen($string);
// % and / are CPU intensive, so, maybe find a better way
$ignored = $strlen % $this->_width;
$ignoredChars = $ignored ? substr($string, -$ignored) : '';
$currentMap = $this->_width;
return ($strlen - $ignored) / $this->_width;
}
/**
* Returns the mapType.
*
* @return int
*/
public function getMapType()
{
return self::MAP_TYPE_FIXED_LEN;
}
/**
* Returns an integer which specifies how many more bytes to read.
*
* A positive integer indicates the number of more bytes to fetch before invoking
* this method again.
*
* A value of zero means this is already a valid character.
* A value of -1 means this cannot possibly be a valid character.
*
* @param string $bytes
* @param int $size
*
* @return int
*/
public function validateByteSequence($bytes, $size)
{
$needed = $this->_width - $size;
return $needed > -1 ? $needed : -1;
}
/**
* Returns the number of bytes which should be read to start each character.
*
* @return int
*/
public function getInitialByteSize()
{
return $this->_width;
}
}
@@ -0,0 +1,84 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Analyzes US-ASCII characters.
*
* @author Chris Corbyn
*/
class Swift_CharacterReader_UsAsciiReader implements Swift_CharacterReader
{
/**
* Returns the complete character map.
*
* @param string $string
* @param int $startOffset
* @param array $currentMap
* @param string $ignoredChars
*
* @return int
*/
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
{
$strlen = strlen($string);
$ignoredChars = '';
for ($i = 0; $i < $strlen; ++$i) {
if ($string[$i] > "\x07F") {
// Invalid char
$currentMap[$i + $startOffset] = $string[$i];
}
}
return $strlen;
}
/**
* Returns mapType.
*
* @return int mapType
*/
public function getMapType()
{
return self::MAP_TYPE_INVALID;
}
/**
* Returns an integer which specifies how many more bytes to read.
*
* A positive integer indicates the number of more bytes to fetch before invoking
* this method again.
* A value of zero means this is already a valid character.
* A value of -1 means this cannot possibly be a valid character.
*
* @param string $bytes
* @param int $size
*
* @return int
*/
public function validateByteSequence($bytes, $size)
{
$byte = reset($bytes);
if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F) {
return 0;
}
return -1;
}
/**
* Returns the number of bytes which should be read to start each character.
*
* @return int
*/
public function getInitialByteSize()
{
return 1;
}
}
@@ -0,0 +1,176 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Analyzes UTF-8 characters.
*
* @author Chris Corbyn
* @author Xavier De Cock <xdecock@gmail.com>
*/
class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader
{
/** Pre-computed for optimization */
private static $length_map = array(
// N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x0N
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1N
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x2N
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x3N
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x4N
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x5N
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x6N
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x7N
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x8N
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x9N
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xAN
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xBN
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xCN
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xDN
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEN
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0, // 0xFN
);
private static $s_length_map = array(
"\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1,
"\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1,
"\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1,
"\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1,
"\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1,
"\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1,
"\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1,
"\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1,
"\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1,
"\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1,
"\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1,
"\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1,
"\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1,
"\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1,
"\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1,
"\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1,
"\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0,
"\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0,
"\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0,
"\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0,
"\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0,
"\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0,
"\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0,
"\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0,
"\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2,
"\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2,
"\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2,
"\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2,
"\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3,
"\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3,
"\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4,
"\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0,
);
/**
* Returns the complete character map.
*
* @param string $string
* @param int $startOffset
* @param array $currentMap
* @param mixed $ignoredChars
*
* @return int
*/
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
{
if (!isset($currentMap['i']) || !isset($currentMap['p'])) {
$currentMap['p'] = $currentMap['i'] = array();
}
$strlen = strlen($string);
$charPos = count($currentMap['p']);
$foundChars = 0;
$invalid = false;
for ($i = 0; $i < $strlen; ++$i) {
$char = $string[$i];
$size = self::$s_length_map[$char];
if ($size == 0) {
/* char is invalid, we must wait for a resync */
$invalid = true;
continue;
} else {
if ($invalid == true) {
/* We mark the chars as invalid and start a new char */
$currentMap['p'][$charPos + $foundChars] = $startOffset + $i;
$currentMap['i'][$charPos + $foundChars] = true;
++$foundChars;
$invalid = false;
}
if (($i + $size) > $strlen) {
$ignoredChars = substr($string, $i);
break;
}
for ($j = 1; $j < $size; ++$j) {
$char = $string[$i + $j];
if ($char > "\x7F" && $char < "\xC0") {
// Valid - continue parsing
} else {
/* char is invalid, we must wait for a resync */
$invalid = true;
continue 2;
}
}
/* Ok we got a complete char here */
$currentMap['p'][$charPos + $foundChars] = $startOffset + $i + $size;
$i += $j - 1;
++$foundChars;
}
}
return $foundChars;
}
/**
* Returns mapType.
*
* @return int mapType
*/
public function getMapType()
{
return self::MAP_TYPE_POSITIONS;
}
/**
* Returns an integer which specifies how many more bytes to read.
*
* A positive integer indicates the number of more bytes to fetch before invoking
* this method again.
* A value of zero means this is already a valid character.
* A value of -1 means this cannot possibly be a valid character.
*
* @param string $bytes
* @param int $size
*
* @return int
*/
public function validateByteSequence($bytes, $size)
{
if ($size < 1) {
return -1;
}
$needed = self::$length_map[$bytes[0]] - $size;
return $needed > -1 ? $needed : -1;
}
/**
* Returns the number of bytes which should be read to start each character.
*
* @return int
*/
public function getInitialByteSize()
{
return 1;
}
}
@@ -0,0 +1,26 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A factory for creating CharacterReaders.
*
* @author Chris Corbyn
*/
interface Swift_CharacterReaderFactory
{
/**
* Returns a CharacterReader suitable for the charset applied.
*
* @param string $charset
*
* @return Swift_CharacterReader
*/
public function getReaderFor($charset);
}
@@ -0,0 +1,124 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Standard factory for creating CharacterReaders.
*
* @author Chris Corbyn
*/
class Swift_CharacterReaderFactory_SimpleCharacterReaderFactory implements Swift_CharacterReaderFactory
{
/**
* A map of charset patterns to their implementation classes.
*
* @var array
*/
private static $_map = array();
/**
* Factories which have already been loaded.
*
* @var Swift_CharacterReaderFactory[]
*/
private static $_loaded = array();
/**
* Creates a new CharacterReaderFactory.
*/
public function __construct()
{
$this->init();
}
public function __wakeup()
{
$this->init();
}
public function init()
{
if (count(self::$_map) > 0) {
return;
}
$prefix = 'Swift_CharacterReader_';
$singleByte = array(
'class' => $prefix.'GenericFixedWidthReader',
'constructor' => array(1),
);
$doubleByte = array(
'class' => $prefix.'GenericFixedWidthReader',
'constructor' => array(2),
);
$fourBytes = array(
'class' => $prefix.'GenericFixedWidthReader',
'constructor' => array(4),
);
// Utf-8
self::$_map['utf-?8'] = array(
'class' => $prefix.'Utf8Reader',
'constructor' => array(),
);
//7-8 bit charsets
self::$_map['(us-)?ascii'] = $singleByte;
self::$_map['(iso|iec)-?8859-?[0-9]+'] = $singleByte;
self::$_map['windows-?125[0-9]'] = $singleByte;
self::$_map['cp-?[0-9]+'] = $singleByte;
self::$_map['ansi'] = $singleByte;
self::$_map['macintosh'] = $singleByte;
self::$_map['koi-?7'] = $singleByte;
self::$_map['koi-?8-?.+'] = $singleByte;
self::$_map['mik'] = $singleByte;
self::$_map['(cork|t1)'] = $singleByte;
self::$_map['v?iscii'] = $singleByte;
//16 bits
self::$_map['(ucs-?2|utf-?16)'] = $doubleByte;
//32 bits
self::$_map['(ucs-?4|utf-?32)'] = $fourBytes;
// Fallback
self::$_map['.*'] = $singleByte;
}
/**
* Returns a CharacterReader suitable for the charset applied.
*
* @param string $charset
*
* @return Swift_CharacterReader
*/
public function getReaderFor($charset)
{
$charset = trim(strtolower($charset));
foreach (self::$_map as $pattern => $spec) {
$re = '/^'.$pattern.'$/D';
if (preg_match($re, $charset)) {
if (!array_key_exists($pattern, self::$_loaded)) {
$reflector = new ReflectionClass($spec['class']);
if ($reflector->getConstructor()) {
$reader = $reflector->newInstanceArgs($spec['constructor']);
} else {
$reader = $reflector->newInstance();
}
self::$_loaded[$pattern] = $reader;
}
return self::$_loaded[$pattern];
}
}
}
}
@@ -0,0 +1,89 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An abstract means of reading and writing data in terms of characters as opposed
* to bytes.
*
* Classes implementing this interface may use a subsystem which requires less
* memory than working with large strings of data.
*
* @author Chris Corbyn
*/
interface Swift_CharacterStream
{
/**
* Set the character set used in this CharacterStream.
*
* @param string $charset
*/
public function setCharacterSet($charset);
/**
* Set the CharacterReaderFactory for multi charset support.
*
* @param Swift_CharacterReaderFactory $factory
*/
public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory);
/**
* Overwrite this character stream using the byte sequence in the byte stream.
*
* @param Swift_OutputByteStream $os output stream to read from
*/
public function importByteStream(Swift_OutputByteStream $os);
/**
* Import a string a bytes into this CharacterStream, overwriting any existing
* data in the stream.
*
* @param string $string
*/
public function importString($string);
/**
* Read $length characters from the stream and move the internal pointer
* $length further into the stream.
*
* @param int $length
*
* @return string
*/
public function read($length);
/**
* Read $length characters from the stream and return a 1-dimensional array
* containing there octet values.
*
* @param int $length
*
* @return int[]
*/
public function readBytes($length);
/**
* Write $chars to the end of the stream.
*
* @param string $chars
*/
public function write($chars);
/**
* Move the internal pointer to $charOffset in the stream.
*
* @param int $charOffset
*/
public function setPointer($charOffset);
/**
* Empty the stream and reset the internal pointer.
*/
public function flushContents();
}
@@ -0,0 +1,293 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A CharacterStream implementation which stores characters in an internal array.
*
* @author Chris Corbyn
*/
class Swift_CharacterStream_ArrayCharacterStream implements Swift_CharacterStream
{
/** A map of byte values and their respective characters */
private static $_charMap;
/** A map of characters and their derivative byte values */
private static $_byteMap;
/** The char reader (lazy-loaded) for the current charset */
private $_charReader;
/** A factory for creating CharacterReader instances */
private $_charReaderFactory;
/** The character set this stream is using */
private $_charset;
/** Array of characters */
private $_array = array();
/** Size of the array of character */
private $_array_size = array();
/** The current character offset in the stream */
private $_offset = 0;
/**
* Create a new CharacterStream with the given $chars, if set.
*
* @param Swift_CharacterReaderFactory $factory for loading validators
* @param string $charset used in the stream
*/
public function __construct(Swift_CharacterReaderFactory $factory, $charset)
{
self::_initializeMaps();
$this->setCharacterReaderFactory($factory);
$this->setCharacterSet($charset);
}
/**
* Set the character set used in this CharacterStream.
*
* @param string $charset
*/
public function setCharacterSet($charset)
{
$this->_charset = $charset;
$this->_charReader = null;
}
/**
* Set the CharacterReaderFactory for multi charset support.
*
* @param Swift_CharacterReaderFactory $factory
*/
public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory)
{
$this->_charReaderFactory = $factory;
}
/**
* Overwrite this character stream using the byte sequence in the byte stream.
*
* @param Swift_OutputByteStream $os output stream to read from
*/
public function importByteStream(Swift_OutputByteStream $os)
{
if (!isset($this->_charReader)) {
$this->_charReader = $this->_charReaderFactory
->getReaderFor($this->_charset);
}
$startLength = $this->_charReader->getInitialByteSize();
while (false !== $bytes = $os->read($startLength)) {
$c = array();
for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) {
$c[] = self::$_byteMap[$bytes[$i]];
}
$size = count($c);
$need = $this->_charReader
->validateByteSequence($c, $size);
if ($need > 0 &&
false !== $bytes = $os->read($need)) {
for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) {
$c[] = self::$_byteMap[$bytes[$i]];
}
}
$this->_array[] = $c;
++$this->_array_size;
}
}
/**
* Import a string a bytes into this CharacterStream, overwriting any existing
* data in the stream.
*
* @param string $string
*/
public function importString($string)
{
$this->flushContents();
$this->write($string);
}
/**
* Read $length characters from the stream and move the internal pointer
* $length further into the stream.
*
* @param int $length
*
* @return string
*/
public function read($length)
{
if ($this->_offset == $this->_array_size) {
return false;
}
// Don't use array slice
$arrays = array();
$end = $length + $this->_offset;
for ($i = $this->_offset; $i < $end; ++$i) {
if (!isset($this->_array[$i])) {
break;
}
$arrays[] = $this->_array[$i];
}
$this->_offset += $i - $this->_offset; // Limit function calls
$chars = false;
foreach ($arrays as $array) {
$chars .= implode('', array_map('chr', $array));
}
return $chars;
}
/**
* Read $length characters from the stream and return a 1-dimensional array
* containing there octet values.
*
* @param int $length
*
* @return int[]
*/
public function readBytes($length)
{
if ($this->_offset == $this->_array_size) {
return false;
}
$arrays = array();
$end = $length + $this->_offset;
for ($i = $this->_offset; $i < $end; ++$i) {
if (!isset($this->_array[$i])) {
break;
}
$arrays[] = $this->_array[$i];
}
$this->_offset += ($i - $this->_offset); // Limit function calls
return call_user_func_array('array_merge', $arrays);
}
/**
* Write $chars to the end of the stream.
*
* @param string $chars
*/
public function write($chars)
{
if (!isset($this->_charReader)) {
$this->_charReader = $this->_charReaderFactory->getReaderFor(
$this->_charset);
}
$startLength = $this->_charReader->getInitialByteSize();
$fp = fopen('php://memory', 'w+b');
fwrite($fp, $chars);
unset($chars);
fseek($fp, 0, SEEK_SET);
$buffer = array(0);
$buf_pos = 1;
$buf_len = 1;
$has_datas = true;
do {
$bytes = array();
// Buffer Filing
if ($buf_len - $buf_pos < $startLength) {
$buf = array_splice($buffer, $buf_pos);
$new = $this->_reloadBuffer($fp, 100);
if ($new) {
$buffer = array_merge($buf, $new);
$buf_len = count($buffer);
$buf_pos = 0;
} else {
$has_datas = false;
}
}
if ($buf_len - $buf_pos > 0) {
$size = 0;
for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) {
++$size;
$bytes[] = $buffer[$buf_pos++];
}
$need = $this->_charReader->validateByteSequence(
$bytes, $size);
if ($need > 0) {
if ($buf_len - $buf_pos < $need) {
$new = $this->_reloadBuffer($fp, $need);
if ($new) {
$buffer = array_merge($buffer, $new);
$buf_len = count($buffer);
}
}
for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) {
$bytes[] = $buffer[$buf_pos++];
}
}
$this->_array[] = $bytes;
++$this->_array_size;
}
} while ($has_datas);
fclose($fp);
}
/**
* Move the internal pointer to $charOffset in the stream.
*
* @param int $charOffset
*/
public function setPointer($charOffset)
{
if ($charOffset > $this->_array_size) {
$charOffset = $this->_array_size;
} elseif ($charOffset < 0) {
$charOffset = 0;
}
$this->_offset = $charOffset;
}
/**
* Empty the stream and reset the internal pointer.
*/
public function flushContents()
{
$this->_offset = 0;
$this->_array = array();
$this->_array_size = 0;
}
private function _reloadBuffer($fp, $len)
{
if (!feof($fp) && ($bytes = fread($fp, $len)) !== false) {
$buf = array();
for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) {
$buf[] = self::$_byteMap[$bytes[$i]];
}
return $buf;
}
return false;
}
private static function _initializeMaps()
{
if (!isset(self::$_charMap)) {
self::$_charMap = array();
for ($byte = 0; $byte < 256; ++$byte) {
self::$_charMap[$byte] = chr($byte);
}
self::$_byteMap = array_flip(self::$_charMap);
}
}
}
@@ -0,0 +1,267 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A CharacterStream implementation which stores characters in an internal array.
*
* @author Xavier De Cock <xdecock@gmail.com>
*/
class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream
{
/**
* The char reader (lazy-loaded) for the current charset.
*
* @var Swift_CharacterReader
*/
private $_charReader;
/**
* A factory for creating CharacterReader instances.
*
* @var Swift_CharacterReaderFactory
*/
private $_charReaderFactory;
/**
* The character set this stream is using.
*
* @var string
*/
private $_charset;
/**
* The data's stored as-is.
*
* @var string
*/
private $_datas = '';
/**
* Number of bytes in the stream.
*
* @var int
*/
private $_datasSize = 0;
/**
* Map.
*
* @var mixed
*/
private $_map;
/**
* Map Type.
*
* @var int
*/
private $_mapType = 0;
/**
* Number of characters in the stream.
*
* @var int
*/
private $_charCount = 0;
/**
* Position in the stream.
*
* @var int
*/
private $_currentPos = 0;
/**
* Constructor.
*
* @param Swift_CharacterReaderFactory $factory
* @param string $charset
*/
public function __construct(Swift_CharacterReaderFactory $factory, $charset)
{
$this->setCharacterReaderFactory($factory);
$this->setCharacterSet($charset);
}
/* -- Changing parameters of the stream -- */
/**
* Set the character set used in this CharacterStream.
*
* @param string $charset
*/
public function setCharacterSet($charset)
{
$this->_charset = $charset;
$this->_charReader = null;
$this->_mapType = 0;
}
/**
* Set the CharacterReaderFactory for multi charset support.
*
* @param Swift_CharacterReaderFactory $factory
*/
public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory)
{
$this->_charReaderFactory = $factory;
}
/**
* @see Swift_CharacterStream::flushContents()
*/
public function flushContents()
{
$this->_datas = null;
$this->_map = null;
$this->_charCount = 0;
$this->_currentPos = 0;
$this->_datasSize = 0;
}
/**
* @see Swift_CharacterStream::importByteStream()
*
* @param Swift_OutputByteStream $os
*/
public function importByteStream(Swift_OutputByteStream $os)
{
$this->flushContents();
$blocks = 512;
$os->setReadPointer(0);
while (false !== ($read = $os->read($blocks))) {
$this->write($read);
}
}
/**
* @see Swift_CharacterStream::importString()
*
* @param string $string
*/
public function importString($string)
{
$this->flushContents();
$this->write($string);
}
/**
* @see Swift_CharacterStream::read()
*
* @param int $length
*
* @return string
*/
public function read($length)
{
if ($this->_currentPos >= $this->_charCount) {
return false;
}
$ret = false;
$length = $this->_currentPos + $length > $this->_charCount ? $this->_charCount - $this->_currentPos : $length;
switch ($this->_mapType) {
case Swift_CharacterReader::MAP_TYPE_FIXED_LEN:
$len = $length * $this->_map;
$ret = substr($this->_datas,
$this->_currentPos * $this->_map,
$len);
$this->_currentPos += $length;
break;
case Swift_CharacterReader::MAP_TYPE_INVALID:
$ret = '';
for (; $this->_currentPos < $length; ++$this->_currentPos) {
if (isset($this->_map[$this->_currentPos])) {
$ret .= '?';
} else {
$ret .= $this->_datas[$this->_currentPos];
}
}
break;
case Swift_CharacterReader::MAP_TYPE_POSITIONS:
$end = $this->_currentPos + $length;
$end = $end > $this->_charCount ? $this->_charCount : $end;
$ret = '';
$start = 0;
if ($this->_currentPos > 0) {
$start = $this->_map['p'][$this->_currentPos - 1];
}
$to = $start;
for (; $this->_currentPos < $end; ++$this->_currentPos) {
if (isset($this->_map['i'][$this->_currentPos])) {
$ret .= substr($this->_datas, $start, $to - $start).'?';
$start = $this->_map['p'][$this->_currentPos];
} else {
$to = $this->_map['p'][$this->_currentPos];
}
}
$ret .= substr($this->_datas, $start, $to - $start);
break;
}
return $ret;
}
/**
* @see Swift_CharacterStream::readBytes()
*
* @param int $length
*
* @return int[]
*/
public function readBytes($length)
{
$read = $this->read($length);
if ($read !== false) {
$ret = array_map('ord', str_split($read, 1));
return $ret;
}
return false;
}
/**
* @see Swift_CharacterStream::setPointer()
*
* @param int $charOffset
*/
public function setPointer($charOffset)
{
if ($this->_charCount < $charOffset) {
$charOffset = $this->_charCount;
}
$this->_currentPos = $charOffset;
}
/**
* @see Swift_CharacterStream::write()
*
* @param string $chars
*/
public function write($chars)
{
if (!isset($this->_charReader)) {
$this->_charReader = $this->_charReaderFactory->getReaderFor(
$this->_charset);
$this->_map = array();
$this->_mapType = $this->_charReader->getMapType();
}
$ignored = '';
$this->_datas .= $chars;
$this->_charCount += $this->_charReader->getCharPositions(substr($this->_datas, $this->_datasSize), $this->_datasSize, $this->_map, $ignored);
if ($ignored !== false) {
$this->_datasSize = strlen($this->_datas) - strlen($ignored);
} else {
$this->_datasSize = strlen($this->_datas);
}
}
}
@@ -0,0 +1,63 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2009 Fabien Potencier <fabien.potencier@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Base class for Spools (implements time and message limits).
*
* @author Fabien Potencier
*/
abstract class Swift_ConfigurableSpool implements Swift_Spool
{
/** The maximum number of messages to send per flush */
private $_message_limit;
/** The time limit per flush */
private $_time_limit;
/**
* Sets the maximum number of messages to send per flush.
*
* @param int $limit
*/
public function setMessageLimit($limit)
{
$this->_message_limit = (int) $limit;
}
/**
* Gets the maximum number of messages to send per flush.
*
* @return int The limit
*/
public function getMessageLimit()
{
return $this->_message_limit;
}
/**
* Sets the time limit (in seconds) per flush.
*
* @param int $limit The limit
*/
public function setTimeLimit($limit)
{
$this->_time_limit = (int) $limit;
}
/**
* Gets the time limit (in seconds) per flush.
*
* @return int The limit
*/
public function getTimeLimit()
{
return $this->_time_limit;
}
}
@@ -0,0 +1,373 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Dependency Injection container.
*
* @author Chris Corbyn
*/
class Swift_DependencyContainer
{
/** Constant for literal value types */
const TYPE_VALUE = 0x0001;
/** Constant for new instance types */
const TYPE_INSTANCE = 0x0010;
/** Constant for shared instance types */
const TYPE_SHARED = 0x0100;
/** Constant for aliases */
const TYPE_ALIAS = 0x1000;
/** Singleton instance */
private static $_instance = null;
/** The data container */
private $_store = array();
/** The current endpoint in the data container */
private $_endPoint;
/**
* Constructor should not be used.
*
* Use {@link getInstance()} instead.
*/
public function __construct()
{
}
/**
* Returns a singleton of the DependencyContainer.
*
* @return self
*/
public static function getInstance()
{
if (!isset(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* List the names of all items stored in the Container.
*
* @return array
*/
public function listItems()
{
return array_keys($this->_store);
}
/**
* Test if an item is registered in this container with the given name.
*
* @see register()
*
* @param string $itemName
*
* @return bool
*/
public function has($itemName)
{
return array_key_exists($itemName, $this->_store)
&& isset($this->_store[$itemName]['lookupType']);
}
/**
* Lookup the item with the given $itemName.
*
* @see register()
*
* @param string $itemName
*
* @throws Swift_DependencyException If the dependency is not found
*
* @return mixed
*/
public function lookup($itemName)
{
if (!$this->has($itemName)) {
throw new Swift_DependencyException(
'Cannot lookup dependency "'.$itemName.'" since it is not registered.'
);
}
switch ($this->_store[$itemName]['lookupType']) {
case self::TYPE_ALIAS:
return $this->_createAlias($itemName);
case self::TYPE_VALUE:
return $this->_getValue($itemName);
case self::TYPE_INSTANCE:
return $this->_createNewInstance($itemName);
case self::TYPE_SHARED:
return $this->_createSharedInstance($itemName);
}
}
/**
* Create an array of arguments passed to the constructor of $itemName.
*
* @param string $itemName
*
* @return array
*/
public function createDependenciesFor($itemName)
{
$args = array();
if (isset($this->_store[$itemName]['args'])) {
$args = $this->_resolveArgs($this->_store[$itemName]['args']);
}
return $args;
}
/**
* Register a new dependency with $itemName.
*
* This method returns the current DependencyContainer instance because it
* requires the use of the fluid interface to set the specific details for the
* dependency.
*
* @see asNewInstanceOf(), asSharedInstanceOf(), asValue()
*
* @param string $itemName
*
* @return $this
*/
public function register($itemName)
{
$this->_store[$itemName] = array();
$this->_endPoint = &$this->_store[$itemName];
return $this;
}
/**
* Specify the previously registered item as a literal value.
*
* {@link register()} must be called before this will work.
*
* @param mixed $value
*
* @return $this
*/
public function asValue($value)
{
$endPoint = &$this->_getEndPoint();
$endPoint['lookupType'] = self::TYPE_VALUE;
$endPoint['value'] = $value;
return $this;
}
/**
* Specify the previously registered item as an alias of another item.
*
* @param string $lookup
*
* @return $this
*/
public function asAliasOf($lookup)
{
$endPoint = &$this->_getEndPoint();
$endPoint['lookupType'] = self::TYPE_ALIAS;
$endPoint['ref'] = $lookup;
return $this;
}
/**
* Specify the previously registered item as a new instance of $className.
*
* {@link register()} must be called before this will work.
* Any arguments can be set with {@link withDependencies()},
* {@link addConstructorValue()} or {@link addConstructorLookup()}.
*
* @see withDependencies(), addConstructorValue(), addConstructorLookup()
*
* @param string $className
*
* @return $this
*/
public function asNewInstanceOf($className)
{
$endPoint = &$this->_getEndPoint();
$endPoint['lookupType'] = self::TYPE_INSTANCE;
$endPoint['className'] = $className;
return $this;
}
/**
* Specify the previously registered item as a shared instance of $className.
*
* {@link register()} must be called before this will work.
*
* @param string $className
*
* @return $this
*/
public function asSharedInstanceOf($className)
{
$endPoint = &$this->_getEndPoint();
$endPoint['lookupType'] = self::TYPE_SHARED;
$endPoint['className'] = $className;
return $this;
}
/**
* Specify a list of injected dependencies for the previously registered item.
*
* This method takes an array of lookup names.
*
* @see addConstructorValue(), addConstructorLookup()
*
* @param array $lookups
*
* @return $this
*/
public function withDependencies(array $lookups)
{
$endPoint = &$this->_getEndPoint();
$endPoint['args'] = array();
foreach ($lookups as $lookup) {
$this->addConstructorLookup($lookup);
}
return $this;
}
/**
* Specify a literal (non looked up) value for the constructor of the
* previously registered item.
*
* @see withDependencies(), addConstructorLookup()
*
* @param mixed $value
*
* @return $this
*/
public function addConstructorValue($value)
{
$endPoint = &$this->_getEndPoint();
if (!isset($endPoint['args'])) {
$endPoint['args'] = array();
}
$endPoint['args'][] = array('type' => 'value', 'item' => $value);
return $this;
}
/**
* Specify a dependency lookup for the constructor of the previously
* registered item.
*
* @see withDependencies(), addConstructorValue()
*
* @param string $lookup
*
* @return $this
*/
public function addConstructorLookup($lookup)
{
$endPoint = &$this->_getEndPoint();
if (!isset($this->_endPoint['args'])) {
$endPoint['args'] = array();
}
$endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup);
return $this;
}
/** Get the literal value with $itemName */
private function _getValue($itemName)
{
return $this->_store[$itemName]['value'];
}
/** Resolve an alias to another item */
private function _createAlias($itemName)
{
return $this->lookup($this->_store[$itemName]['ref']);
}
/** Create a fresh instance of $itemName */
private function _createNewInstance($itemName)
{
$reflector = new ReflectionClass($this->_store[$itemName]['className']);
if ($reflector->getConstructor()) {
return $reflector->newInstanceArgs(
$this->createDependenciesFor($itemName)
);
}
return $reflector->newInstance();
}
/** Create and register a shared instance of $itemName */
private function _createSharedInstance($itemName)
{
if (!isset($this->_store[$itemName]['instance'])) {
$this->_store[$itemName]['instance'] = $this->_createNewInstance($itemName);
}
return $this->_store[$itemName]['instance'];
}
/** Get the current endpoint in the store */
private function &_getEndPoint()
{
if (!isset($this->_endPoint)) {
throw new BadMethodCallException(
'Component must first be registered by calling register()'
);
}
return $this->_endPoint;
}
/** Get an argument list with dependencies resolved */
private function _resolveArgs(array $args)
{
$resolved = array();
foreach ($args as $argDefinition) {
switch ($argDefinition['type']) {
case 'lookup':
$resolved[] = $this->_lookupRecursive($argDefinition['item']);
break;
case 'value':
$resolved[] = $argDefinition['item'];
break;
}
}
return $resolved;
}
/** Resolve a single dependency with an collections */
private function _lookupRecursive($item)
{
if (is_array($item)) {
$collection = array();
foreach ($item as $k => $v) {
$collection[$k] = $this->_lookupRecursive($v);
}
return $collection;
}
return $this->lookup($item);
}
}
@@ -0,0 +1,27 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* DependencyException gets thrown when a requested dependency is missing.
*
* @author Chris Corbyn
*/
class Swift_DependencyException extends Swift_SwiftException
{
/**
* Create a new DependencyException with $message.
*
* @param string $message
*/
public function __construct($message)
{
parent::__construct($message);
}
}
@@ -0,0 +1,69 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An embedded file, in a multipart message.
*
* @author Chris Corbyn
*/
class Swift_EmbeddedFile extends Swift_Mime_EmbeddedFile
{
/**
* Create a new EmbeddedFile.
*
* Details may be optionally provided to the constructor.
*
* @param string|Swift_OutputByteStream $data
* @param string $filename
* @param string $contentType
*/
public function __construct($data = null, $filename = null, $contentType = null)
{
call_user_func_array(
array($this, 'Swift_Mime_EmbeddedFile::__construct'),
Swift_DependencyContainer::getInstance()
->createDependenciesFor('mime.embeddedfile')
);
$this->setBody($data);
$this->setFilename($filename);
if ($contentType) {
$this->setContentType($contentType);
}
}
/**
* Create a new EmbeddedFile.
*
* @param string|Swift_OutputByteStream $data
* @param string $filename
* @param string $contentType
*
* @return Swift_Mime_EmbeddedFile
*/
public static function newInstance($data = null, $filename = null, $contentType = null)
{
return new self($data, $filename, $contentType);
}
/**
* Create a new EmbeddedFile from a filesystem path.
*
* @param string $path
*
* @return Swift_Mime_EmbeddedFile
*/
public static function fromPath($path)
{
return self::newInstance()->setFile(
new Swift_ByteStream_FileByteStream($path)
);
}
}
@@ -0,0 +1,28 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface for all Encoder schemes.
*
* @author Chris Corbyn
*/
interface Swift_Encoder extends Swift_Mime_CharsetObserver
{
/**
* Encode a given string to produce an encoded string.
*
* @param string $string
* @param int $firstLineOffset if first line needs to be shorter
* @param int $maxLineLength - 0 indicates the default length for this encoding
*
* @return string
*/
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0);
}
@@ -0,0 +1,58 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles Base 64 Encoding in Swift Mailer.
*
* @author Chris Corbyn
*/
class Swift_Encoder_Base64Encoder implements Swift_Encoder
{
/**
* Takes an unencoded string and produces a Base64 encoded string from it.
*
* Base64 encoded strings have a maximum line length of 76 characters.
* If the first line needs to be shorter, indicate the difference with
* $firstLineOffset.
*
* @param string $string to encode
* @param int $firstLineOffset
* @param int $maxLineLength optional, 0 indicates the default of 76 bytes
*
* @return string
*/
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
{
if (0 >= $maxLineLength || 76 < $maxLineLength) {
$maxLineLength = 76;
}
$encodedString = base64_encode($string);
$firstLine = '';
if (0 != $firstLineOffset) {
$firstLine = substr(
$encodedString, 0, $maxLineLength - $firstLineOffset
)."\r\n";
$encodedString = substr(
$encodedString, $maxLineLength - $firstLineOffset
);
}
return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n"));
}
/**
* Does nothing.
*/
public function charsetChanged($charset)
{
}
}
@@ -0,0 +1,300 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles Quoted Printable (QP) Encoding in Swift Mailer.
*
* Possibly the most accurate RFC 2045 QP implementation found in PHP.
*
* @author Chris Corbyn
*/
class Swift_Encoder_QpEncoder implements Swift_Encoder
{
/**
* The CharacterStream used for reading characters (as opposed to bytes).
*
* @var Swift_CharacterStream
*/
protected $_charStream;
/**
* A filter used if input should be canonicalized.
*
* @var Swift_StreamFilter
*/
protected $_filter;
/**
* Pre-computed QP for HUGE optimization.
*
* @var string[]
*/
protected static $_qpMap = array(
0 => '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04',
5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09',
10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E',
15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13',
20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18',
25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D',
30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22',
35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27',
40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C',
45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31',
50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36',
55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B',
60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40',
65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45',
70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A',
75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F',
80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54',
85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59',
90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E',
95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63',
100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68',
105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D',
110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72',
115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77',
120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C',
125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81',
130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86',
135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B',
140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90',
145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95',
150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A',
155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F',
160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4',
165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9',
170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE',
175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3',
180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8',
185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD',
190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2',
195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7',
200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC',
205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1',
210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6',
215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB',
220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0',
225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5',
230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA',
235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF',
240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4',
245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9',
250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE',
255 => '=FF',
);
protected static $_safeMapShare = array();
/**
* A map of non-encoded ascii characters.
*
* @var string[]
*/
protected $_safeMap = array();
/**
* Creates a new QpEncoder for the given CharacterStream.
*
* @param Swift_CharacterStream $charStream to use for reading characters
* @param Swift_StreamFilter $filter if input should be canonicalized
*/
public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null)
{
$this->_charStream = $charStream;
if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) {
$this->initSafeMap();
self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap;
} else {
$this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()];
}
$this->_filter = $filter;
}
public function __sleep()
{
return array('_charStream', '_filter');
}
public function __wakeup()
{
if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) {
$this->initSafeMap();
self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap;
} else {
$this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()];
}
}
protected function getSafeMapShareId()
{
return get_class($this);
}
protected function initSafeMap()
{
foreach (array_merge(
array(0x09, 0x20), range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) {
$this->_safeMap[$byte] = chr($byte);
}
}
/**
* Takes an unencoded string and produces a QP encoded string from it.
*
* QP encoded strings have a maximum line length of 76 characters.
* If the first line needs to be shorter, indicate the difference with
* $firstLineOffset.
*
* @param string $string to encode
* @param int $firstLineOffset, optional
* @param int $maxLineLength, optional 0 indicates the default of 76 chars
*
* @return string
*/
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
{
if ($maxLineLength > 76 || $maxLineLength <= 0) {
$maxLineLength = 76;
}
$thisLineLength = $maxLineLength - $firstLineOffset;
$lines = array();
$lNo = 0;
$lines[$lNo] = '';
$currentLine = &$lines[$lNo++];
$size = $lineLen = 0;
$this->_charStream->flushContents();
$this->_charStream->importString($string);
// Fetching more than 4 chars at one is slower, as is fetching fewer bytes
// Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6
// bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes
while (false !== $bytes = $this->_nextSequence()) {
// If we're filtering the input
if (isset($this->_filter)) {
// If we can't filter because we need more bytes
while ($this->_filter->shouldBuffer($bytes)) {
// Then collect bytes into the buffer
if (false === $moreBytes = $this->_nextSequence(1)) {
break;
}
foreach ($moreBytes as $b) {
$bytes[] = $b;
}
}
// And filter them
$bytes = $this->_filter->filter($bytes);
}
$enc = $this->_encodeByteSequence($bytes, $size);
$i = strpos($enc, '=0D=0A');
$newLineLength = $lineLen + ($i === false ? $size : $i);
if ($currentLine && $newLineLength >= $thisLineLength) {
$lines[$lNo] = '';
$currentLine = &$lines[$lNo++];
$thisLineLength = $maxLineLength;
$lineLen = 0;
}
$currentLine .= $enc;
if ($i === false) {
$lineLen += $size;
} else {
// 6 is the length of '=0D=0A'.
$lineLen = $size - strrpos($enc, '=0D=0A') - 6;
}
}
return $this->_standardize(implode("=\r\n", $lines));
}
/**
* Updates the charset used.
*
* @param string $charset
*/
public function charsetChanged($charset)
{
$this->_charStream->setCharacterSet($charset);
}
/**
* Encode the given byte array into a verbatim QP form.
*
* @param int[] $bytes
* @param int $size
*
* @return string
*/
protected function _encodeByteSequence(array $bytes, &$size)
{
$ret = '';
$size = 0;
foreach ($bytes as $b) {
if (isset($this->_safeMap[$b])) {
$ret .= $this->_safeMap[$b];
++$size;
} else {
$ret .= self::$_qpMap[$b];
$size += 3;
}
}
return $ret;
}
/**
* Get the next sequence of bytes to read from the char stream.
*
* @param int $size number of bytes to read
*
* @return int[]
*/
protected function _nextSequence($size = 4)
{
return $this->_charStream->readBytes($size);
}
/**
* Make sure CRLF is correct and HT/SPACE are in valid places.
*
* @param string $string
*
* @return string
*/
protected function _standardize($string)
{
$string = str_replace(array("\t=0D=0A", ' =0D=0A', '=0D=0A'),
array("=09\r\n", "=20\r\n", "\r\n"), $string
);
switch ($end = ord(substr($string, -1))) {
case 0x09:
case 0x20:
$string = substr_replace($string, self::$_qpMap[$end], -1);
}
return $string;
}
/**
* Make a deep copy of object.
*/
public function __clone()
{
$this->_charStream = clone $this->_charStream;
}
}
@@ -0,0 +1,92 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles RFC 2231 specified Encoding in Swift Mailer.
*
* @author Chris Corbyn
*/
class Swift_Encoder_Rfc2231Encoder implements Swift_Encoder
{
/**
* A character stream to use when reading a string as characters instead of bytes.
*
* @var Swift_CharacterStream
*/
private $_charStream;
/**
* Creates a new Rfc2231Encoder using the given character stream instance.
*
* @param Swift_CharacterStream
*/
public function __construct(Swift_CharacterStream $charStream)
{
$this->_charStream = $charStream;
}
/**
* Takes an unencoded string and produces a string encoded according to
* RFC 2231 from it.
*
* @param string $string
* @param int $firstLineOffset
* @param int $maxLineLength optional, 0 indicates the default of 75 bytes
*
* @return string
*/
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
{
$lines = array();
$lineCount = 0;
$lines[] = '';
$currentLine = &$lines[$lineCount++];
if (0 >= $maxLineLength) {
$maxLineLength = 75;
}
$this->_charStream->flushContents();
$this->_charStream->importString($string);
$thisLineLength = $maxLineLength - $firstLineOffset;
while (false !== $char = $this->_charStream->read(4)) {
$encodedChar = rawurlencode($char);
if (0 != strlen($currentLine)
&& strlen($currentLine.$encodedChar) > $thisLineLength) {
$lines[] = '';
$currentLine = &$lines[$lineCount++];
$thisLineLength = $maxLineLength;
}
$currentLine .= $encodedChar;
}
return implode("\r\n", $lines);
}
/**
* Updates the charset used.
*
* @param string $charset
*/
public function charsetChanged($charset)
{
$this->_charStream->setCharacterSet($charset);
}
/**
* Make a deep copy of object.
*/
public function __clone()
{
$this->_charStream = clone $this->_charStream;
}
}
@@ -0,0 +1,62 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Provides quick access to each encoding type.
*
* @author Chris Corbyn
*/
class Swift_Encoding
{
/**
* Get the Encoder that provides 7-bit encoding.
*
* @return Swift_Mime_ContentEncoder
*/
public static function get7BitEncoding()
{
return self::_lookup('mime.7bitcontentencoder');
}
/**
* Get the Encoder that provides 8-bit encoding.
*
* @return Swift_Mime_ContentEncoder
*/
public static function get8BitEncoding()
{
return self::_lookup('mime.8bitcontentencoder');
}
/**
* Get the Encoder that provides Quoted-Printable (QP) encoding.
*
* @return Swift_Mime_ContentEncoder
*/
public static function getQpEncoding()
{
return self::_lookup('mime.qpcontentencoder');
}
/**
* Get the Encoder that provides Base64 encoding.
*
* @return Swift_Mime_ContentEncoder
*/
public static function getBase64Encoding()
{
return self::_lookup('mime.base64contentencoder');
}
private static function _lookup($key)
{
return Swift_DependencyContainer::getInstance()->lookup($key);
}
}
@@ -0,0 +1,65 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Generated when a command is sent over an SMTP connection.
*
* @author Chris Corbyn
*/
class Swift_Events_CommandEvent extends Swift_Events_EventObject
{
/**
* The command sent to the server.
*
* @var string
*/
private $_command;
/**
* An array of codes which a successful response will contain.
*
* @var int[]
*/
private $_successCodes = array();
/**
* Create a new CommandEvent for $source with $command.
*
* @param Swift_Transport $source
* @param string $command
* @param array $successCodes
*/
public function __construct(Swift_Transport $source, $command, $successCodes = array())
{
parent::__construct($source);
$this->_command = $command;
$this->_successCodes = $successCodes;
}
/**
* Get the command which was sent to the server.
*
* @return string
*/
public function getCommand()
{
return $this->_command;
}
/**
* Get the numeric response codes which indicate success for this command.
*
* @return int[]
*/
public function getSuccessCodes()
{
return $this->_successCodes;
}
}
@@ -0,0 +1,24 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Listens for Transports to send commands to the server.
*
* @author Chris Corbyn
*/
interface Swift_Events_CommandListener extends Swift_Events_EventListener
{
/**
* Invoked immediately following a command being sent.
*
* @param Swift_Events_CommandEvent $evt
*/
public function commandSent(Swift_Events_CommandEvent $evt);
}
@@ -0,0 +1,38 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* The minimum interface for an Event.
*
* @author Chris Corbyn
*/
interface Swift_Events_Event
{
/**
* Get the source object of this event.
*
* @return object
*/
public function getSource();
/**
* Prevent this Event from bubbling any further up the stack.
*
* @param bool $cancel, optional
*/
public function cancelBubble($cancel = true);
/**
* Returns true if this Event will not bubble any further up the stack.
*
* @return bool
*/
public function bubbleCancelled();
}
@@ -0,0 +1,83 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface for the EventDispatcher which handles the event dispatching layer.
*
* @author Chris Corbyn
*/
interface Swift_Events_EventDispatcher
{
/**
* Create a new SendEvent for $source and $message.
*
* @param Swift_Transport $source
* @param Swift_Mime_Message
*
* @return Swift_Events_SendEvent
*/
public function createSendEvent(Swift_Transport $source, Swift_Mime_Message $message);
/**
* Create a new CommandEvent for $source and $command.
*
* @param Swift_Transport $source
* @param string $command That will be executed
* @param array $successCodes That are needed
*
* @return Swift_Events_CommandEvent
*/
public function createCommandEvent(Swift_Transport $source, $command, $successCodes = array());
/**
* Create a new ResponseEvent for $source and $response.
*
* @param Swift_Transport $source
* @param string $response
* @param bool $valid If the response is valid
*
* @return Swift_Events_ResponseEvent
*/
public function createResponseEvent(Swift_Transport $source, $response, $valid);
/**
* Create a new TransportChangeEvent for $source.
*
* @param Swift_Transport $source
*
* @return Swift_Events_TransportChangeEvent
*/
public function createTransportChangeEvent(Swift_Transport $source);
/**
* Create a new TransportExceptionEvent for $source.
*
* @param Swift_Transport $source
* @param Swift_TransportException $ex
*
* @return Swift_Events_TransportExceptionEvent
*/
public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex);
/**
* Bind an event listener to this dispatcher.
*
* @param Swift_Events_EventListener $listener
*/
public function bindEventListener(Swift_Events_EventListener $listener);
/**
* Dispatch the given Event to all suitable listeners.
*
* @param Swift_Events_EventObject $evt
* @param string $target method
*/
public function dispatchEvent(Swift_Events_EventObject $evt, $target);
}
@@ -0,0 +1,18 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An identity interface which all EventListeners must extend.
*
* @author Chris Corbyn
*/
interface Swift_Events_EventListener
{
}
@@ -0,0 +1,63 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A base Event which all Event classes inherit from.
*
* @author Chris Corbyn
*/
class Swift_Events_EventObject implements Swift_Events_Event
{
/** The source of this Event */
private $_source;
/** The state of this Event (should it bubble up the stack?) */
private $_bubbleCancelled = false;
/**
* Create a new EventObject originating at $source.
*
* @param object $source
*/
public function __construct($source)
{
$this->_source = $source;
}
/**
* Get the source object of this event.
*
* @return object
*/
public function getSource()
{
return $this->_source;
}
/**
* Prevent this Event from bubbling any further up the stack.
*
* @param bool $cancel, optional
*/
public function cancelBubble($cancel = true)
{
$this->_bubbleCancelled = $cancel;
}
/**
* Returns true if this Event will not bubble any further up the stack.
*
* @return bool
*/
public function bubbleCancelled()
{
return $this->_bubbleCancelled;
}
}
@@ -0,0 +1,65 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Generated when a response is received on a SMTP connection.
*
* @author Chris Corbyn
*/
class Swift_Events_ResponseEvent extends Swift_Events_EventObject
{
/**
* The overall result.
*
* @var bool
*/
private $_valid;
/**
* The response received from the server.
*
* @var string
*/
private $_response;
/**
* Create a new ResponseEvent for $source and $response.
*
* @param Swift_Transport $source
* @param string $response
* @param bool $valid
*/
public function __construct(Swift_Transport $source, $response, $valid = false)
{
parent::__construct($source);
$this->_response = $response;
$this->_valid = $valid;
}
/**
* Get the response which was received from the server.
*
* @return string
*/
public function getResponse()
{
return $this->_response;
}
/**
* Get the success status of this Event.
*
* @return bool
*/
public function isValid()
{
return $this->_valid;
}
}
@@ -0,0 +1,24 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Listens for responses from a remote SMTP server.
*
* @author Chris Corbyn
*/
interface Swift_Events_ResponseListener extends Swift_Events_EventListener
{
/**
* Invoked immediately following a response coming back.
*
* @param Swift_Events_ResponseEvent $evt
*/
public function responseReceived(Swift_Events_ResponseEvent $evt);
}
@@ -0,0 +1,129 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Generated when a message is being sent.
*
* @author Chris Corbyn
*/
class Swift_Events_SendEvent extends Swift_Events_EventObject
{
/** Sending has yet to occur */
const RESULT_PENDING = 0x0001;
/** Email is spooled, ready to be sent */
const RESULT_SPOOLED = 0x0011;
/** Sending was successful */
const RESULT_SUCCESS = 0x0010;
/** Sending worked, but there were some failures */
const RESULT_TENTATIVE = 0x0100;
/** Sending failed */
const RESULT_FAILED = 0x1000;
/**
* The Message being sent.
*
* @var Swift_Mime_Message
*/
private $_message;
/**
* Any recipients which failed after sending.
*
* @var string[]
*/
private $_failedRecipients = array();
/**
* The overall result as a bitmask from the class constants.
*
* @var int
*/
private $_result;
/**
* Create a new SendEvent for $source and $message.
*
* @param Swift_Transport $source
* @param Swift_Mime_Message $message
*/
public function __construct(Swift_Transport $source, Swift_Mime_Message $message)
{
parent::__construct($source);
$this->_message = $message;
$this->_result = self::RESULT_PENDING;
}
/**
* Get the Transport used to send the Message.
*
* @return Swift_Transport
*/
public function getTransport()
{
return $this->getSource();
}
/**
* Get the Message being sent.
*
* @return Swift_Mime_Message
*/
public function getMessage()
{
return $this->_message;
}
/**
* Set the array of addresses that failed in sending.
*
* @param array $recipients
*/
public function setFailedRecipients($recipients)
{
$this->_failedRecipients = $recipients;
}
/**
* Get an recipient addresses which were not accepted for delivery.
*
* @return string[]
*/
public function getFailedRecipients()
{
return $this->_failedRecipients;
}
/**
* Set the result of sending.
*
* @param int $result
*/
public function setResult($result)
{
$this->_result = $result;
}
/**
* Get the result of this Event.
*
* The return value is a bitmask from
* {@see RESULT_PENDING, RESULT_SUCCESS, RESULT_TENTATIVE, RESULT_FAILED}
*
* @return int
*/
public function getResult()
{
return $this->_result;
}
}
@@ -0,0 +1,31 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Listens for Messages being sent from within the Transport system.
*
* @author Chris Corbyn
*/
interface Swift_Events_SendListener extends Swift_Events_EventListener
{
/**
* Invoked immediately before the Message is sent.
*
* @param Swift_Events_SendEvent $evt
*/
public function beforeSendPerformed(Swift_Events_SendEvent $evt);
/**
* Invoked immediately after the Message is sent.
*
* @param Swift_Events_SendEvent $evt
*/
public function sendPerformed(Swift_Events_SendEvent $evt);
}
@@ -0,0 +1,156 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* The EventDispatcher which handles the event dispatching layer.
*
* @author Chris Corbyn
*/
class Swift_Events_SimpleEventDispatcher implements Swift_Events_EventDispatcher
{
/** A map of event types to their associated listener types */
private $_eventMap = array();
/** Event listeners bound to this dispatcher */
private $_listeners = array();
/** Listeners queued to have an Event bubbled up the stack to them */
private $_bubbleQueue = array();
/**
* Create a new EventDispatcher.
*/
public function __construct()
{
$this->_eventMap = array(
'Swift_Events_CommandEvent' => 'Swift_Events_CommandListener',
'Swift_Events_ResponseEvent' => 'Swift_Events_ResponseListener',
'Swift_Events_SendEvent' => 'Swift_Events_SendListener',
'Swift_Events_TransportChangeEvent' => 'Swift_Events_TransportChangeListener',
'Swift_Events_TransportExceptionEvent' => 'Swift_Events_TransportExceptionListener',
);
}
/**
* Create a new SendEvent for $source and $message.
*
* @param Swift_Transport $source
* @param Swift_Mime_Message
*
* @return Swift_Events_SendEvent
*/
public function createSendEvent(Swift_Transport $source, Swift_Mime_Message $message)
{
return new Swift_Events_SendEvent($source, $message);
}
/**
* Create a new CommandEvent for $source and $command.
*
* @param Swift_Transport $source
* @param string $command That will be executed
* @param array $successCodes That are needed
*
* @return Swift_Events_CommandEvent
*/
public function createCommandEvent(Swift_Transport $source, $command, $successCodes = array())
{
return new Swift_Events_CommandEvent($source, $command, $successCodes);
}
/**
* Create a new ResponseEvent for $source and $response.
*
* @param Swift_Transport $source
* @param string $response
* @param bool $valid If the response is valid
*
* @return Swift_Events_ResponseEvent
*/
public function createResponseEvent(Swift_Transport $source, $response, $valid)
{
return new Swift_Events_ResponseEvent($source, $response, $valid);
}
/**
* Create a new TransportChangeEvent for $source.
*
* @param Swift_Transport $source
*
* @return Swift_Events_TransportChangeEvent
*/
public function createTransportChangeEvent(Swift_Transport $source)
{
return new Swift_Events_TransportChangeEvent($source);
}
/**
* Create a new TransportExceptionEvent for $source.
*
* @param Swift_Transport $source
* @param Swift_TransportException $ex
*
* @return Swift_Events_TransportExceptionEvent
*/
public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex)
{
return new Swift_Events_TransportExceptionEvent($source, $ex);
}
/**
* Bind an event listener to this dispatcher.
*
* @param Swift_Events_EventListener $listener
*/
public function bindEventListener(Swift_Events_EventListener $listener)
{
foreach ($this->_listeners as $l) {
// Already loaded
if ($l === $listener) {
return;
}
}
$this->_listeners[] = $listener;
}
/**
* Dispatch the given Event to all suitable listeners.
*
* @param Swift_Events_EventObject $evt
* @param string $target method
*/
public function dispatchEvent(Swift_Events_EventObject $evt, $target)
{
$this->_prepareBubbleQueue($evt);
$this->_bubble($evt, $target);
}
/** Queue listeners on a stack ready for $evt to be bubbled up it */
private function _prepareBubbleQueue(Swift_Events_EventObject $evt)
{
$this->_bubbleQueue = array();
$evtClass = get_class($evt);
foreach ($this->_listeners as $listener) {
if (array_key_exists($evtClass, $this->_eventMap)
&& ($listener instanceof $this->_eventMap[$evtClass])) {
$this->_bubbleQueue[] = $listener;
}
}
}
/** Bubble $evt up the stack calling $target() on each listener */
private function _bubble(Swift_Events_EventObject $evt, $target)
{
if (!$evt->bubbleCancelled() && $listener = array_shift($this->_bubbleQueue)) {
$listener->$target($evt);
$this->_bubble($evt, $target);
}
}
}
@@ -0,0 +1,27 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Generated when the state of a Transport is changed (i.e. stopped/started).
*
* @author Chris Corbyn
*/
class Swift_Events_TransportChangeEvent extends Swift_Events_EventObject
{
/**
* Get the Transport.
*
* @return Swift_Transport
*/
public function getTransport()
{
return $this->getSource();
}
}
@@ -0,0 +1,45 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Listens for changes within the Transport system.
*
* @author Chris Corbyn
*/
interface Swift_Events_TransportChangeListener extends Swift_Events_EventListener
{
/**
* Invoked just before a Transport is started.
*
* @param Swift_Events_TransportChangeEvent $evt
*/
public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt);
/**
* Invoked immediately after the Transport is started.
*
* @param Swift_Events_TransportChangeEvent $evt
*/
public function transportStarted(Swift_Events_TransportChangeEvent $evt);
/**
* Invoked just before a Transport is stopped.
*
* @param Swift_Events_TransportChangeEvent $evt
*/
public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt);
/**
* Invoked immediately after the Transport is stopped.
*
* @param Swift_Events_TransportChangeEvent $evt
*/
public function transportStopped(Swift_Events_TransportChangeEvent $evt);
}
@@ -0,0 +1,46 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Generated when a TransportException is thrown from the Transport system.
*
* @author Chris Corbyn
*/
class Swift_Events_TransportExceptionEvent extends Swift_Events_EventObject
{
/**
* The Exception thrown.
*
* @var Swift_TransportException
*/
private $_exception;
/**
* Create a new TransportExceptionEvent for $transport.
*
* @param Swift_Transport $transport
* @param Swift_TransportException $ex
*/
public function __construct(Swift_Transport $transport, Swift_TransportException $ex)
{
parent::__construct($transport);
$this->_exception = $ex;
}
/**
* Get the TransportException thrown.
*
* @return Swift_TransportException
*/
public function getException()
{
return $this->_exception;
}
}
@@ -0,0 +1,24 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Listens for Exceptions thrown from within the Transport system.
*
* @author Chris Corbyn
*/
interface Swift_Events_TransportExceptionListener extends Swift_Events_EventListener
{
/**
* Invoked as a TransportException is thrown in the Transport system.
*
* @param Swift_Events_TransportExceptionEvent $evt
*/
public function exceptionThrown(Swift_Events_TransportExceptionEvent $evt);
}
@@ -0,0 +1,45 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Contains a list of redundant Transports so when one fails, the next is used.
*
* @author Chris Corbyn
*/
class Swift_FailoverTransport extends Swift_Transport_FailoverTransport
{
/**
* Creates a new FailoverTransport with $transports.
*
* @param Swift_Transport[] $transports
*/
public function __construct($transports = array())
{
call_user_func_array(
array($this, 'Swift_Transport_FailoverTransport::__construct'),
Swift_DependencyContainer::getInstance()
->createDependenciesFor('transport.failover')
);
$this->setTransports($transports);
}
/**
* Create a new FailoverTransport instance.
*
* @param Swift_Transport[] $transports
*
* @return self
*/
public static function newInstance($transports = array())
{
return new self($transports);
}
}
@@ -0,0 +1,208 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2009 Fabien Potencier <fabien.potencier@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Stores Messages on the filesystem.
*
* @author Fabien Potencier
* @author Xavier De Cock <xdecock@gmail.com>
*/
class Swift_FileSpool extends Swift_ConfigurableSpool
{
/** The spool directory */
private $_path;
/**
* File WriteRetry Limit.
*
* @var int
*/
private $_retryLimit = 10;
/**
* Create a new FileSpool.
*
* @param string $path
*
* @throws Swift_IoException
*/
public function __construct($path)
{
$this->_path = $path;
if (!file_exists($this->_path)) {
if (!mkdir($this->_path, 0777, true)) {
throw new Swift_IoException(sprintf('Unable to create path "%s".', $this->_path));
}
}
}
/**
* Tests if this Spool mechanism has started.
*
* @return bool
*/
public function isStarted()
{
return true;
}
/**
* Starts this Spool mechanism.
*/
public function start()
{
}
/**
* Stops this Spool mechanism.
*/
public function stop()
{
}
/**
* Allow to manage the enqueuing retry limit.
*
* Default, is ten and allows over 64^20 different fileNames
*
* @param int $limit
*/
public function setRetryLimit($limit)
{
$this->_retryLimit = $limit;
}
/**
* Queues a message.
*
* @param Swift_Mime_Message $message The message to store
*
* @throws Swift_IoException
*
* @return bool
*/
public function queueMessage(Swift_Mime_Message $message)
{
$ser = serialize($message);
$fileName = $this->_path.'/'.$this->getRandomString(10);
for ($i = 0; $i < $this->_retryLimit; ++$i) {
/* We try an exclusive creation of the file. This is an atomic operation, it avoid locking mechanism */
$fp = @fopen($fileName.'.message', 'x');
if (false !== $fp) {
if (false === fwrite($fp, $ser)) {
return false;
}
return fclose($fp);
} else {
/* The file already exists, we try a longer fileName */
$fileName .= $this->getRandomString(1);
}
}
throw new Swift_IoException(sprintf('Unable to create a file for enqueuing Message in "%s".', $this->_path));
}
/**
* Execute a recovery if for any reason a process is sending for too long.
*
* @param int $timeout in second Defaults is for very slow smtp responses
*/
public function recover($timeout = 900)
{
foreach (new DirectoryIterator($this->_path) as $file) {
$file = $file->getRealPath();
if (substr($file, -16) == '.message.sending') {
$lockedtime = filectime($file);
if ((time() - $lockedtime) > $timeout) {
rename($file, substr($file, 0, -8));
}
}
}
}
/**
* Sends messages using the given transport instance.
*
* @param Swift_Transport $transport A transport instance
* @param string[] $failedRecipients An array of failures by-reference
*
* @return int The number of sent e-mail's
*/
public function flushQueue(Swift_Transport $transport, &$failedRecipients = null)
{
$directoryIterator = new DirectoryIterator($this->_path);
/* Start the transport only if there are queued files to send */
if (!$transport->isStarted()) {
foreach ($directoryIterator as $file) {
if (substr($file->getRealPath(), -8) == '.message') {
$transport->start();
break;
}
}
}
$failedRecipients = (array) $failedRecipients;
$count = 0;
$time = time();
foreach ($directoryIterator as $file) {
$file = $file->getRealPath();
if (substr($file, -8) != '.message') {
continue;
}
/* We try a rename, it's an atomic operation, and avoid locking the file */
if (rename($file, $file.'.sending')) {
$message = unserialize(file_get_contents($file.'.sending'));
$count += $transport->send($message, $failedRecipients);
unlink($file.'.sending');
} else {
/* This message has just been catched by another process */
continue;
}
if ($this->getMessageLimit() && $count >= $this->getMessageLimit()) {
break;
}
if ($this->getTimeLimit() && (time() - $time) >= $this->getTimeLimit()) {
break;
}
}
return $count;
}
/**
* Returns a random string needed to generate a fileName for the queue.
*
* @param int $count
*
* @return string
*/
protected function getRandomString($count)
{
// This string MUST stay FS safe, avoid special chars
$base = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';
$ret = '';
$strlen = strlen($base);
for ($i = 0; $i < $count; ++$i) {
$ret .= $base[((int) rand(0, $strlen - 1))];
}
return $ret;
}
}
@@ -0,0 +1,24 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An OutputByteStream which specifically reads from a file.
*
* @author Chris Corbyn
*/
interface Swift_FileStream extends Swift_OutputByteStream
{
/**
* Get the complete path to the file.
*
* @return string
*/
public function getPath();
}
@@ -0,0 +1,32 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Allows StreamFilters to operate on a stream.
*
* @author Chris Corbyn
*/
interface Swift_Filterable
{
/**
* Add a new StreamFilter, referenced by $key.
*
* @param Swift_StreamFilter $filter
* @param string $key
*/
public function addFilter(Swift_StreamFilter $filter, $key);
/**
* Remove an existing filter using $key.
*
* @param string $key
*/
public function removeFilter($key);
}
@@ -0,0 +1,57 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An image, embedded in a multipart message.
*
* @author Chris Corbyn
*/
class Swift_Image extends Swift_EmbeddedFile
{
/**
* Create a new EmbeddedFile.
*
* Details may be optionally provided to the constructor.
*
* @param string|Swift_OutputByteStream $data
* @param string $filename
* @param string $contentType
*/
public function __construct($data = null, $filename = null, $contentType = null)
{
parent::__construct($data, $filename, $contentType);
}
/**
* Create a new Image.
*
* @param string|Swift_OutputByteStream $data
* @param string $filename
* @param string $contentType
*
* @return self
*/
public static function newInstance($data = null, $filename = null, $contentType = null)
{
return new self($data, $filename, $contentType);
}
/**
* Create a new Image from a filesystem path.
*
* @param string $path
*
* @return self
*/
public static function fromPath($path)
{
return self::newInstance()->setFile(new Swift_ByteStream_FileByteStream($path));
}
}
@@ -0,0 +1,75 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An abstract means of writing data.
*
* Classes implementing this interface may use a subsystem which requires less
* memory than working with large strings of data.
*
* @author Chris Corbyn
*/
interface Swift_InputByteStream
{
/**
* Writes $bytes to the end of the stream.
*
* Writing may not happen immediately if the stream chooses to buffer. If
* you want to write these bytes with immediate effect, call {@link commit()}
* after calling write().
*
* This method returns the sequence ID of the write (i.e. 1 for first, 2 for
* second, etc etc).
*
* @param string $bytes
*
* @throws Swift_IoException
*
* @return int
*/
public function write($bytes);
/**
* For any bytes that are currently buffered inside the stream, force them
* off the buffer.
*
* @throws Swift_IoException
*/
public function commit();
/**
* Attach $is to this stream.
*
* The stream acts as an observer, receiving all data that is written.
* All {@link write()} and {@link flushBuffers()} operations will be mirrored.
*
* @param Swift_InputByteStream $is
*/
public function bind(Swift_InputByteStream $is);
/**
* Remove an already bound stream.
*
* If $is is not bound, no errors will be raised.
* If the stream currently has any buffered data it will be written to $is
* before unbinding occurs.
*
* @param Swift_InputByteStream $is
*/
public function unbind(Swift_InputByteStream $is);
/**
* Flush the contents of the stream (empty it) and set the internal pointer
* to the beginning.
*
* @throws Swift_IoException
*/
public function flushBuffers();
}
@@ -0,0 +1,29 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* I/O Exception class.
*
* @author Chris Corbyn
*/
class Swift_IoException extends Swift_SwiftException
{
/**
* Create a new IoException with $message.
*
* @param string $message
* @param int $code
* @param Exception $previous
*/
public function __construct($message, $code = 0, Exception $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
@@ -0,0 +1,105 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Provides a mechanism for storing data using two keys.
*
* @author Chris Corbyn
*/
interface Swift_KeyCache
{
/** Mode for replacing existing cached data */
const MODE_WRITE = 1;
/** Mode for appending data to the end of existing cached data */
const MODE_APPEND = 2;
/**
* Set a string into the cache under $itemKey for the namespace $nsKey.
*
* @see MODE_WRITE, MODE_APPEND
*
* @param string $nsKey
* @param string $itemKey
* @param string $string
* @param int $mode
*/
public function setString($nsKey, $itemKey, $string, $mode);
/**
* Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
*
* @see MODE_WRITE, MODE_APPEND
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_OutputByteStream $os
* @param int $mode
*/
public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode);
/**
* Provides a ByteStream which when written to, writes data to $itemKey.
*
* NOTE: The stream will always write in append mode.
* If the optional third parameter is passed all writes will go through $is.
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_InputByteStream $is optional input stream
*
* @return Swift_InputByteStream
*/
public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $is = null);
/**
* Get data back out of the cache as a string.
*
* @param string $nsKey
* @param string $itemKey
*
* @return string
*/
public function getString($nsKey, $itemKey);
/**
* Get data back out of the cache as a ByteStream.
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_InputByteStream $is stream to write the data to
*/
public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is);
/**
* Check if the given $itemKey exists in the namespace $nsKey.
*
* @param string $nsKey
* @param string $itemKey
*
* @return bool
*/
public function hasKey($nsKey, $itemKey);
/**
* Clear data for $itemKey in the namespace $nsKey if it exists.
*
* @param string $nsKey
* @param string $itemKey
*/
public function clearKey($nsKey, $itemKey);
/**
* Clear all data in the namespace $nsKey if it exists.
*
* @param string $nsKey
*/
public function clearAll($nsKey);
}
@@ -0,0 +1,206 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A basic KeyCache backed by an array.
*
* @author Chris Corbyn
*/
class Swift_KeyCache_ArrayKeyCache implements Swift_KeyCache
{
/**
* Cache contents.
*
* @var array
*/
private $_contents = array();
/**
* An InputStream for cloning.
*
* @var Swift_KeyCache_KeyCacheInputStream
*/
private $_stream;
/**
* Create a new ArrayKeyCache with the given $stream for cloning to make
* InputByteStreams.
*
* @param Swift_KeyCache_KeyCacheInputStream $stream
*/
public function __construct(Swift_KeyCache_KeyCacheInputStream $stream)
{
$this->_stream = $stream;
}
/**
* Set a string into the cache under $itemKey for the namespace $nsKey.
*
* @see MODE_WRITE, MODE_APPEND
*
* @param string $nsKey
* @param string $itemKey
* @param string $string
* @param int $mode
*/
public function setString($nsKey, $itemKey, $string, $mode)
{
$this->_prepareCache($nsKey);
switch ($mode) {
case self::MODE_WRITE:
$this->_contents[$nsKey][$itemKey] = $string;
break;
case self::MODE_APPEND:
if (!$this->hasKey($nsKey, $itemKey)) {
$this->_contents[$nsKey][$itemKey] = '';
}
$this->_contents[$nsKey][$itemKey] .= $string;
break;
default:
throw new Swift_SwiftException(
'Invalid mode ['.$mode.'] used to set nsKey='.
$nsKey.', itemKey='.$itemKey
);
}
}
/**
* Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
*
* @see MODE_WRITE, MODE_APPEND
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_OutputByteStream $os
* @param int $mode
*/
public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode)
{
$this->_prepareCache($nsKey);
switch ($mode) {
case self::MODE_WRITE:
$this->clearKey($nsKey, $itemKey);
case self::MODE_APPEND:
if (!$this->hasKey($nsKey, $itemKey)) {
$this->_contents[$nsKey][$itemKey] = '';
}
while (false !== $bytes = $os->read(8192)) {
$this->_contents[$nsKey][$itemKey] .= $bytes;
}
break;
default:
throw new Swift_SwiftException(
'Invalid mode ['.$mode.'] used to set nsKey='.
$nsKey.', itemKey='.$itemKey
);
}
}
/**
* Provides a ByteStream which when written to, writes data to $itemKey.
*
* NOTE: The stream will always write in append mode.
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_InputByteStream $writeThrough
*
* @return Swift_InputByteStream
*/
public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null)
{
$is = clone $this->_stream;
$is->setKeyCache($this);
$is->setNsKey($nsKey);
$is->setItemKey($itemKey);
if (isset($writeThrough)) {
$is->setWriteThroughStream($writeThrough);
}
return $is;
}
/**
* Get data back out of the cache as a string.
*
* @param string $nsKey
* @param string $itemKey
*
* @return string
*/
public function getString($nsKey, $itemKey)
{
$this->_prepareCache($nsKey);
if ($this->hasKey($nsKey, $itemKey)) {
return $this->_contents[$nsKey][$itemKey];
}
}
/**
* Get data back out of the cache as a ByteStream.
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_InputByteStream $is to write the data to
*/
public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is)
{
$this->_prepareCache($nsKey);
$is->write($this->getString($nsKey, $itemKey));
}
/**
* Check if the given $itemKey exists in the namespace $nsKey.
*
* @param string $nsKey
* @param string $itemKey
*
* @return bool
*/
public function hasKey($nsKey, $itemKey)
{
$this->_prepareCache($nsKey);
return array_key_exists($itemKey, $this->_contents[$nsKey]);
}
/**
* Clear data for $itemKey in the namespace $nsKey if it exists.
*
* @param string $nsKey
* @param string $itemKey
*/
public function clearKey($nsKey, $itemKey)
{
unset($this->_contents[$nsKey][$itemKey]);
}
/**
* Clear all data in the namespace $nsKey if it exists.
*
* @param string $nsKey
*/
public function clearAll($nsKey)
{
unset($this->_contents[$nsKey]);
}
/**
* Initialize the namespace of $nsKey if needed.
*
* @param string $nsKey
*/
private function _prepareCache($nsKey)
{
if (!array_key_exists($nsKey, $this->_contents)) {
$this->_contents[$nsKey] = array();
}
}
}
@@ -0,0 +1,321 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A KeyCache which streams to and from disk.
*
* @author Chris Corbyn
*/
class Swift_KeyCache_DiskKeyCache implements Swift_KeyCache
{
/** Signal to place pointer at start of file */
const POSITION_START = 0;
/** Signal to place pointer at end of file */
const POSITION_END = 1;
/** Signal to leave pointer in whatever position it currently is */
const POSITION_CURRENT = 2;
/**
* An InputStream for cloning.
*
* @var Swift_KeyCache_KeyCacheInputStream
*/
private $_stream;
/**
* A path to write to.
*
* @var string
*/
private $_path;
/**
* Stored keys.
*
* @var array
*/
private $_keys = array();
/**
* Will be true if magic_quotes_runtime is turned on.
*
* @var bool
*/
private $_quotes = false;
/**
* Create a new DiskKeyCache with the given $stream for cloning to make
* InputByteStreams, and the given $path to save to.
*
* @param Swift_KeyCache_KeyCacheInputStream $stream
* @param string $path to save to
*/
public function __construct(Swift_KeyCache_KeyCacheInputStream $stream, $path)
{
$this->_stream = $stream;
$this->_path = $path;
if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) {
$this->_quotes = true;
}
}
/**
* Set a string into the cache under $itemKey for the namespace $nsKey.
*
* @see MODE_WRITE, MODE_APPEND
*
* @param string $nsKey
* @param string $itemKey
* @param string $string
* @param int $mode
*
* @throws Swift_IoException
*/
public function setString($nsKey, $itemKey, $string, $mode)
{
$this->_prepareCache($nsKey);
switch ($mode) {
case self::MODE_WRITE:
$fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START);
break;
case self::MODE_APPEND:
$fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END);
break;
default:
throw new Swift_SwiftException(
'Invalid mode ['.$mode.'] used to set nsKey='.
$nsKey.', itemKey='.$itemKey
);
break;
}
fwrite($fp, $string);
$this->_freeHandle($nsKey, $itemKey);
}
/**
* Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
*
* @see MODE_WRITE, MODE_APPEND
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_OutputByteStream $os
* @param int $mode
*
* @throws Swift_IoException
*/
public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode)
{
$this->_prepareCache($nsKey);
switch ($mode) {
case self::MODE_WRITE:
$fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START);
break;
case self::MODE_APPEND:
$fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END);
break;
default:
throw new Swift_SwiftException(
'Invalid mode ['.$mode.'] used to set nsKey='.
$nsKey.', itemKey='.$itemKey
);
break;
}
while (false !== $bytes = $os->read(8192)) {
fwrite($fp, $bytes);
}
$this->_freeHandle($nsKey, $itemKey);
}
/**
* Provides a ByteStream which when written to, writes data to $itemKey.
*
* NOTE: The stream will always write in append mode.
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_InputByteStream $writeThrough
*
* @return Swift_InputByteStream
*/
public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null)
{
$is = clone $this->_stream;
$is->setKeyCache($this);
$is->setNsKey($nsKey);
$is->setItemKey($itemKey);
if (isset($writeThrough)) {
$is->setWriteThroughStream($writeThrough);
}
return $is;
}
/**
* Get data back out of the cache as a string.
*
* @param string $nsKey
* @param string $itemKey
*
* @throws Swift_IoException
*
* @return string
*/
public function getString($nsKey, $itemKey)
{
$this->_prepareCache($nsKey);
if ($this->hasKey($nsKey, $itemKey)) {
$fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START);
if ($this->_quotes) {
ini_set('magic_quotes_runtime', 0);
}
$str = '';
while (!feof($fp) && false !== $bytes = fread($fp, 8192)) {
$str .= $bytes;
}
if ($this->_quotes) {
ini_set('magic_quotes_runtime', 1);
}
$this->_freeHandle($nsKey, $itemKey);
return $str;
}
}
/**
* Get data back out of the cache as a ByteStream.
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_InputByteStream $is to write the data to
*/
public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is)
{
if ($this->hasKey($nsKey, $itemKey)) {
$fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START);
if ($this->_quotes) {
ini_set('magic_quotes_runtime', 0);
}
while (!feof($fp) && false !== $bytes = fread($fp, 8192)) {
$is->write($bytes);
}
if ($this->_quotes) {
ini_set('magic_quotes_runtime', 1);
}
$this->_freeHandle($nsKey, $itemKey);
}
}
/**
* Check if the given $itemKey exists in the namespace $nsKey.
*
* @param string $nsKey
* @param string $itemKey
*
* @return bool
*/
public function hasKey($nsKey, $itemKey)
{
return is_file($this->_path.'/'.$nsKey.'/'.$itemKey);
}
/**
* Clear data for $itemKey in the namespace $nsKey if it exists.
*
* @param string $nsKey
* @param string $itemKey
*/
public function clearKey($nsKey, $itemKey)
{
if ($this->hasKey($nsKey, $itemKey)) {
$this->_freeHandle($nsKey, $itemKey);
unlink($this->_path.'/'.$nsKey.'/'.$itemKey);
}
}
/**
* Clear all data in the namespace $nsKey if it exists.
*
* @param string $nsKey
*/
public function clearAll($nsKey)
{
if (array_key_exists($nsKey, $this->_keys)) {
foreach ($this->_keys[$nsKey] as $itemKey => $null) {
$this->clearKey($nsKey, $itemKey);
}
if (is_dir($this->_path.'/'.$nsKey)) {
rmdir($this->_path.'/'.$nsKey);
}
unset($this->_keys[$nsKey]);
}
}
/**
* Initialize the namespace of $nsKey if needed.
*
* @param string $nsKey
*/
private function _prepareCache($nsKey)
{
$cacheDir = $this->_path.'/'.$nsKey;
if (!is_dir($cacheDir)) {
if (!mkdir($cacheDir)) {
throw new Swift_IoException('Failed to create cache directory '.$cacheDir);
}
$this->_keys[$nsKey] = array();
}
}
/**
* Get a file handle on the cache item.
*
* @param string $nsKey
* @param string $itemKey
* @param int $position
*
* @return resource
*/
private function _getHandle($nsKey, $itemKey, $position)
{
if (!isset($this->_keys[$nsKey][$itemKey])) {
$openMode = $this->hasKey($nsKey, $itemKey) ? 'r+b' : 'w+b';
$fp = fopen($this->_path.'/'.$nsKey.'/'.$itemKey, $openMode);
$this->_keys[$nsKey][$itemKey] = $fp;
}
if (self::POSITION_START == $position) {
fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_SET);
} elseif (self::POSITION_END == $position) {
fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_END);
}
return $this->_keys[$nsKey][$itemKey];
}
private function _freeHandle($nsKey, $itemKey)
{
$fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_CURRENT);
fclose($fp);
$this->_keys[$nsKey][$itemKey] = null;
}
/**
* Destructor.
*/
public function __destruct()
{
foreach ($this->_keys as $nsKey => $null) {
$this->clearAll($nsKey);
}
}
}
@@ -0,0 +1,51 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Writes data to a KeyCache using a stream.
*
* @author Chris Corbyn
*/
interface Swift_KeyCache_KeyCacheInputStream extends Swift_InputByteStream
{
/**
* Set the KeyCache to wrap.
*
* @param Swift_KeyCache $keyCache
*/
public function setKeyCache(Swift_KeyCache $keyCache);
/**
* Set the nsKey which will be written to.
*
* @param string $nsKey
*/
public function setNsKey($nsKey);
/**
* Set the itemKey which will be written to.
*
* @param string $itemKey
*/
public function setItemKey($itemKey);
/**
* Specify a stream to write through for each write().
*
* @param Swift_InputByteStream $is
*/
public function setWriteThroughStream(Swift_InputByteStream $is);
/**
* Any implementation should be cloneable, allowing the clone to access a
* separate $nsKey and $itemKey.
*/
public function __clone();
}
@@ -0,0 +1,115 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A null KeyCache that does not cache at all.
*
* @author Chris Corbyn
*/
class Swift_KeyCache_NullKeyCache implements Swift_KeyCache
{
/**
* Set a string into the cache under $itemKey for the namespace $nsKey.
*
* @see MODE_WRITE, MODE_APPEND
*
* @param string $nsKey
* @param string $itemKey
* @param string $string
* @param int $mode
*/
public function setString($nsKey, $itemKey, $string, $mode)
{
}
/**
* Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
*
* @see MODE_WRITE, MODE_APPEND
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_OutputByteStream $os
* @param int $mode
*/
public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode)
{
}
/**
* Provides a ByteStream which when written to, writes data to $itemKey.
*
* NOTE: The stream will always write in append mode.
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_InputByteStream $writeThrough
*
* @return Swift_InputByteStream
*/
public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null)
{
}
/**
* Get data back out of the cache as a string.
*
* @param string $nsKey
* @param string $itemKey
*
* @return string
*/
public function getString($nsKey, $itemKey)
{
}
/**
* Get data back out of the cache as a ByteStream.
*
* @param string $nsKey
* @param string $itemKey
* @param Swift_InputByteStream $is to write the data to
*/
public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is)
{
}
/**
* Check if the given $itemKey exists in the namespace $nsKey.
*
* @param string $nsKey
* @param string $itemKey
*
* @return bool
*/
public function hasKey($nsKey, $itemKey)
{
return false;
}
/**
* Clear data for $itemKey in the namespace $nsKey if it exists.
*
* @param string $nsKey
* @param string $itemKey
*/
public function clearKey($nsKey, $itemKey)
{
}
/**
* Clear all data in the namespace $nsKey if it exists.
*
* @param string $nsKey
*/
public function clearAll($nsKey)
{
}
}
@@ -0,0 +1,127 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Writes data to a KeyCache using a stream.
*
* @author Chris Corbyn
*/
class Swift_KeyCache_SimpleKeyCacheInputStream implements Swift_KeyCache_KeyCacheInputStream
{
/** The KeyCache being written to */
private $_keyCache;
/** The nsKey of the KeyCache being written to */
private $_nsKey;
/** The itemKey of the KeyCache being written to */
private $_itemKey;
/** A stream to write through on each write() */
private $_writeThrough = null;
/**
* Set the KeyCache to wrap.
*
* @param Swift_KeyCache $keyCache
*/
public function setKeyCache(Swift_KeyCache $keyCache)
{
$this->_keyCache = $keyCache;
}
/**
* Specify a stream to write through for each write().
*
* @param Swift_InputByteStream $is
*/
public function setWriteThroughStream(Swift_InputByteStream $is)
{
$this->_writeThrough = $is;
}
/**
* Writes $bytes to the end of the stream.
*
* @param string $bytes
* @param Swift_InputByteStream $is optional
*/
public function write($bytes, Swift_InputByteStream $is = null)
{
$this->_keyCache->setString(
$this->_nsKey, $this->_itemKey, $bytes, Swift_KeyCache::MODE_APPEND
);
if (isset($is)) {
$is->write($bytes);
}
if (isset($this->_writeThrough)) {
$this->_writeThrough->write($bytes);
}
}
/**
* Not used.
*/
public function commit()
{
}
/**
* Not used.
*/
public function bind(Swift_InputByteStream $is)
{
}
/**
* Not used.
*/
public function unbind(Swift_InputByteStream $is)
{
}
/**
* Flush the contents of the stream (empty it) and set the internal pointer
* to the beginning.
*/
public function flushBuffers()
{
$this->_keyCache->clearKey($this->_nsKey, $this->_itemKey);
}
/**
* Set the nsKey which will be written to.
*
* @param string $nsKey
*/
public function setNsKey($nsKey)
{
$this->_nsKey = $nsKey;
}
/**
* Set the itemKey which will be written to.
*
* @param string $itemKey
*/
public function setItemKey($itemKey)
{
$this->_itemKey = $itemKey;
}
/**
* Any implementation should be cloneable, allowing the clone to access a
* separate $nsKey and $itemKey.
*/
public function __clone()
{
$this->_writeThrough = null;
}
}
@@ -0,0 +1,45 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Redundantly and rotationally uses several Transport implementations when sending.
*
* @author Chris Corbyn
*/
class Swift_LoadBalancedTransport extends Swift_Transport_LoadBalancedTransport
{
/**
* Creates a new LoadBalancedTransport with $transports.
*
* @param array $transports
*/
public function __construct($transports = array())
{
call_user_func_array(
array($this, 'Swift_Transport_LoadBalancedTransport::__construct'),
Swift_DependencyContainer::getInstance()
->createDependenciesFor('transport.loadbalanced')
);
$this->setTransports($transports);
}
/**
* Create a new LoadBalancedTransport instance.
*
* @param array $transports
*
* @return self
*/
public static function newInstance($transports = array())
{
return new self($transports);
}
}
@@ -0,0 +1,47 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Sends Messages using the mail() function.
*
* @author Chris Corbyn
*
* @deprecated since 5.4.5 (to be removed in 6.0)
*/
class Swift_MailTransport extends Swift_Transport_MailTransport
{
/**
* Create a new MailTransport, optionally specifying $extraParams.
*
* @param string $extraParams
*/
public function __construct($extraParams = '-f%s')
{
call_user_func_array(
array($this, 'Swift_Transport_MailTransport::__construct'),
Swift_DependencyContainer::getInstance()
->createDependenciesFor('transport.mail')
);
$this->setExtraParams($extraParams);
}
/**
* Create a new MailTransport instance.
*
* @param string $extraParams To be passed to mail()
*
* @return self
*/
public static function newInstance($extraParams = '-f%s')
{
return new self($extraParams);
}
}
@@ -0,0 +1,114 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Swift Mailer class.
*
* @author Chris Corbyn
*/
class Swift_Mailer
{
/** The Transport used to send messages */
private $_transport;
/**
* Create a new Mailer using $transport for delivery.
*
* @param Swift_Transport $transport
*/
public function __construct(Swift_Transport $transport)
{
$this->_transport = $transport;
}
/**
* Create a new Mailer instance.
*
* @param Swift_Transport $transport
*
* @return self
*/
public static function newInstance(Swift_Transport $transport)
{
return new self($transport);
}
/**
* Create a new class instance of one of the message services.
*
* For example 'mimepart' would create a 'message.mimepart' instance
*
* @param string $service
*
* @return object
*/
public function createMessage($service = 'message')
{
return Swift_DependencyContainer::getInstance()
->lookup('message.'.$service);
}
/**
* Send the given Message like it would be sent in a mail client.
*
* All recipients (with the exception of Bcc) will be able to see the other
* recipients this message was sent to.
*
* Recipient/sender data will be retrieved from the Message object.
*
* The return value is the number of recipients who were accepted for
* delivery.
*
* @param Swift_Mime_Message $message
* @param array $failedRecipients An array of failures by-reference
*
* @return int The number of successful recipients. Can be 0 which indicates failure
*/
public function send(Swift_Mime_Message $message, &$failedRecipients = null)
{
$failedRecipients = (array) $failedRecipients;
if (!$this->_transport->isStarted()) {
$this->_transport->start();
}
$sent = 0;
try {
$sent = $this->_transport->send($message, $failedRecipients);
} catch (Swift_RfcComplianceException $e) {
foreach ($message->getTo() as $address => $name) {
$failedRecipients[] = $address;
}
}
return $sent;
}
/**
* Register a plugin using a known unique key (e.g. myPlugin).
*
* @param Swift_Events_EventListener $plugin
*/
public function registerPlugin(Swift_Events_EventListener $plugin)
{
$this->_transport->registerPlugin($plugin);
}
/**
* The Transport used to send messages.
*
* @return Swift_Transport
*/
public function getTransport()
{
return $this->_transport;
}
}
@@ -0,0 +1,55 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Wraps a standard PHP array in an iterator.
*
* @author Chris Corbyn
*/
class Swift_Mailer_ArrayRecipientIterator implements Swift_Mailer_RecipientIterator
{
/**
* The list of recipients.
*
* @var array
*/
private $_recipients = array();
/**
* Create a new ArrayRecipientIterator from $recipients.
*
* @param array $recipients
*/
public function __construct(array $recipients)
{
$this->_recipients = $recipients;
}
/**
* Returns true only if there are more recipients to send to.
*
* @return bool
*/
public function hasNext()
{
return !empty($this->_recipients);
}
/**
* Returns an array where the keys are the addresses of recipients and the
* values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL).
*
* @return array
*/
public function nextRecipient()
{
return array_splice($this->_recipients, 0, 1);
}
}
@@ -0,0 +1,32 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Provides an abstract way of specifying recipients for batch sending.
*
* @author Chris Corbyn
*/
interface Swift_Mailer_RecipientIterator
{
/**
* Returns true only if there are more recipients to send to.
*
* @return bool
*/
public function hasNext();
/**
* Returns an array where the keys are the addresses of recipients and the
* values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL).
*
* @return array
*/
public function nextRecipient();
}
@@ -0,0 +1,110 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2011 Fabien Potencier <fabien.potencier@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Stores Messages in memory.
*
* @author Fabien Potencier
*/
class Swift_MemorySpool implements Swift_Spool
{
protected $messages = array();
private $flushRetries = 3;
/**
* Tests if this Transport mechanism has started.
*
* @return bool
*/
public function isStarted()
{
return true;
}
/**
* Starts this Transport mechanism.
*/
public function start()
{
}
/**
* Stops this Transport mechanism.
*/
public function stop()
{
}
/**
* @param int $retries
*/
public function setFlushRetries($retries)
{
$this->flushRetries = $retries;
}
/**
* Stores a message in the queue.
*
* @param Swift_Mime_Message $message The message to store
*
* @return bool Whether the operation has succeeded
*/
public function queueMessage(Swift_Mime_Message $message)
{
//clone the message to make sure it is not changed while in the queue
$this->messages[] = clone $message;
return true;
}
/**
* Sends messages using the given transport instance.
*
* @param Swift_Transport $transport A transport instance
* @param string[] $failedRecipients An array of failures by-reference
*
* @return int The number of sent emails
*/
public function flushQueue(Swift_Transport $transport, &$failedRecipients = null)
{
if (!$this->messages) {
return 0;
}
if (!$transport->isStarted()) {
$transport->start();
}
$count = 0;
$retries = $this->flushRetries;
while ($retries--) {
try {
while ($message = array_pop($this->messages)) {
$count += $transport->send($message, $failedRecipients);
}
} catch (Swift_TransportException $exception) {
if ($retries) {
// re-queue the message at the end of the queue to give a chance
// to the other messages to be sent, in case the failure was due to
// this message and not just the transport failing
array_unshift($this->messages, $message);
// wait half a second before we try again
usleep(500000);
} else {
throw $exception;
}
}
}
return $count;
}
}
@@ -0,0 +1,289 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* The Message class for building emails.
*
* @author Chris Corbyn
*/
class Swift_Message extends Swift_Mime_SimpleMessage
{
/**
* @var Swift_Signers_HeaderSigner[]
*/
private $headerSigners = array();
/**
* @var Swift_Signers_BodySigner[]
*/
private $bodySigners = array();
/**
* @var array
*/
private $savedMessage = array();
/**
* Create a new Message.
*
* Details may be optionally passed into the constructor.
*
* @param string $subject
* @param string $body
* @param string $contentType
* @param string $charset
*/
public function __construct($subject = null, $body = null, $contentType = null, $charset = null)
{
call_user_func_array(
array($this, 'Swift_Mime_SimpleMessage::__construct'),
Swift_DependencyContainer::getInstance()
->createDependenciesFor('mime.message')
);
if (!isset($charset)) {
$charset = Swift_DependencyContainer::getInstance()
->lookup('properties.charset');
}
$this->setSubject($subject);
$this->setBody($body);
$this->setCharset($charset);
if ($contentType) {
$this->setContentType($contentType);
}
}
/**
* Create a new Message.
*
* @param string $subject
* @param string $body
* @param string $contentType
* @param string $charset
*
* @return $this
*/
public static function newInstance($subject = null, $body = null, $contentType = null, $charset = null)
{
return new self($subject, $body, $contentType, $charset);
}
/**
* Add a MimePart to this Message.
*
* @param string|Swift_OutputByteStream $body
* @param string $contentType
* @param string $charset
*
* @return $this
*/
public function addPart($body, $contentType = null, $charset = null)
{
return $this->attach(Swift_MimePart::newInstance($body, $contentType, $charset)->setEncoder($this->getEncoder()));
}
/**
* Detach a signature handler from a message.
*
* @param Swift_Signer $signer
*
* @return $this
*/
public function attachSigner(Swift_Signer $signer)
{
if ($signer instanceof Swift_Signers_HeaderSigner) {
$this->headerSigners[] = $signer;
} elseif ($signer instanceof Swift_Signers_BodySigner) {
$this->bodySigners[] = $signer;
}
return $this;
}
/**
* Attach a new signature handler to the message.
*
* @param Swift_Signer $signer
*
* @return $this
*/
public function detachSigner(Swift_Signer $signer)
{
if ($signer instanceof Swift_Signers_HeaderSigner) {
foreach ($this->headerSigners as $k => $headerSigner) {
if ($headerSigner === $signer) {
unset($this->headerSigners[$k]);
return $this;
}
}
} elseif ($signer instanceof Swift_Signers_BodySigner) {
foreach ($this->bodySigners as $k => $bodySigner) {
if ($bodySigner === $signer) {
unset($this->bodySigners[$k]);
return $this;
}
}
}
return $this;
}
/**
* Get this message as a complete string.
*
* @return string
*/
public function toString()
{
if (empty($this->headerSigners) && empty($this->bodySigners)) {
return parent::toString();
}
$this->saveMessage();
$this->doSign();
$string = parent::toString();
$this->restoreMessage();
return $string;
}
/**
* Write this message to a {@link Swift_InputByteStream}.
*
* @param Swift_InputByteStream $is
*/
public function toByteStream(Swift_InputByteStream $is)
{
if (empty($this->headerSigners) && empty($this->bodySigners)) {
parent::toByteStream($is);
return;
}
$this->saveMessage();
$this->doSign();
parent::toByteStream($is);
$this->restoreMessage();
}
public function __wakeup()
{
Swift_DependencyContainer::getInstance()->createDependenciesFor('mime.message');
}
/**
* loops through signers and apply the signatures.
*/
protected function doSign()
{
foreach ($this->bodySigners as $signer) {
$altered = $signer->getAlteredHeaders();
$this->saveHeaders($altered);
$signer->signMessage($this);
}
foreach ($this->headerSigners as $signer) {
$altered = $signer->getAlteredHeaders();
$this->saveHeaders($altered);
$signer->reset();
$signer->setHeaders($this->getHeaders());
$signer->startBody();
$this->_bodyToByteStream($signer);
$signer->endBody();
$signer->addSignature($this->getHeaders());
}
}
/**
* save the message before any signature is applied.
*/
protected function saveMessage()
{
$this->savedMessage = array('headers' => array());
$this->savedMessage['body'] = $this->getBody();
$this->savedMessage['children'] = $this->getChildren();
if (count($this->savedMessage['children']) > 0 && $this->getBody() != '') {
$this->setChildren(array_merge(array($this->_becomeMimePart()), $this->savedMessage['children']));
$this->setBody('');
}
}
/**
* save the original headers.
*
* @param array $altered
*/
protected function saveHeaders(array $altered)
{
foreach ($altered as $head) {
$lc = strtolower($head);
if (!isset($this->savedMessage['headers'][$lc])) {
$this->savedMessage['headers'][$lc] = $this->getHeaders()->getAll($head);
}
}
}
/**
* Remove or restore altered headers.
*/
protected function restoreHeaders()
{
foreach ($this->savedMessage['headers'] as $name => $savedValue) {
$headers = $this->getHeaders()->getAll($name);
foreach ($headers as $key => $value) {
if (!isset($savedValue[$key])) {
$this->getHeaders()->remove($name, $key);
}
}
}
}
/**
* Restore message body.
*/
protected function restoreMessage()
{
$this->setBody($this->savedMessage['body']);
$this->setChildren($this->savedMessage['children']);
$this->restoreHeaders();
$this->savedMessage = array();
}
/**
* Clone Message Signers.
*
* @see Swift_Mime_SimpleMimeEntity::__clone()
*/
public function __clone()
{
parent::__clone();
foreach ($this->bodySigners as $key => $bodySigner) {
$this->bodySigners[$key] = clone $bodySigner;
}
foreach ($this->headerSigners as $key => $headerSigner) {
$this->headerSigners[$key] = clone $headerSigner;
}
}
}
@@ -0,0 +1,149 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An attachment, in a multipart message.
*
* @author Chris Corbyn
*/
class Swift_Mime_Attachment extends Swift_Mime_SimpleMimeEntity
{
/** Recognized MIME types */
private $_mimeTypes = array();
/**
* Create a new Attachment with $headers, $encoder and $cache.
*
* @param Swift_Mime_HeaderSet $headers
* @param Swift_Mime_ContentEncoder $encoder
* @param Swift_KeyCache $cache
* @param Swift_Mime_Grammar $grammar
* @param array $mimeTypes optional
*/
public function __construct(Swift_Mime_HeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_Mime_Grammar $grammar, $mimeTypes = array())
{
parent::__construct($headers, $encoder, $cache, $grammar);
$this->setDisposition('attachment');
$this->setContentType('application/octet-stream');
$this->_mimeTypes = $mimeTypes;
}
/**
* Get the nesting level used for this attachment.
*
* Always returns {@link LEVEL_MIXED}.
*
* @return int
*/
public function getNestingLevel()
{
return self::LEVEL_MIXED;
}
/**
* Get the Content-Disposition of this attachment.
*
* By default attachments have a disposition of "attachment".
*
* @return string
*/
public function getDisposition()
{
return $this->_getHeaderFieldModel('Content-Disposition');
}
/**
* Set the Content-Disposition of this attachment.
*
* @param string $disposition
*
* @return $this
*/
public function setDisposition($disposition)
{
if (!$this->_setHeaderFieldModel('Content-Disposition', $disposition)) {
$this->getHeaders()->addParameterizedHeader('Content-Disposition', $disposition);
}
return $this;
}
/**
* Get the filename of this attachment when downloaded.
*
* @return string
*/
public function getFilename()
{
return $this->_getHeaderParameter('Content-Disposition', 'filename');
}
/**
* Set the filename of this attachment.
*
* @param string $filename
*
* @return $this
*/
public function setFilename($filename)
{
$this->_setHeaderParameter('Content-Disposition', 'filename', $filename);
$this->_setHeaderParameter('Content-Type', 'name', $filename);
return $this;
}
/**
* Get the file size of this attachment.
*
* @return int
*/
public function getSize()
{
return $this->_getHeaderParameter('Content-Disposition', 'size');
}
/**
* Set the file size of this attachment.
*
* @param int $size
*
* @return $this
*/
public function setSize($size)
{
$this->_setHeaderParameter('Content-Disposition', 'size', $size);
return $this;
}
/**
* Set the file that this attachment is for.
*
* @param Swift_FileStream $file
* @param string $contentType optional
*
* @return $this
*/
public function setFile(Swift_FileStream $file, $contentType = null)
{
$this->setFilename(basename($file->getPath()));
$this->setBody($file, $contentType);
if (!isset($contentType)) {
$extension = strtolower(substr($file->getPath(), strrpos($file->getPath(), '.') + 1));
if (array_key_exists($extension, $this->_mimeTypes)) {
$this->setContentType($this->_mimeTypes[$extension]);
}
}
return $this;
}
}
@@ -0,0 +1,24 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Observes changes in an Mime entity's character set.
*
* @author Chris Corbyn
*/
interface Swift_Mime_CharsetObserver
{
/**
* Notify this observer that the entity's charset has changed.
*
* @param string $charset
*/
public function charsetChanged($charset);
}
@@ -0,0 +1,34 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface for all Transfer Encoding schemes.
*
* @author Chris Corbyn
*/
interface Swift_Mime_ContentEncoder extends Swift_Encoder
{
/**
* Encode $in to $out.
*
* @param Swift_OutputByteStream $os to read from
* @param Swift_InputByteStream $is to write to
* @param int $firstLineOffset
* @param int $maxLineLength - 0 indicates the default length for this encoding
*/
public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0);
/**
* Get the MIME name of this content encoding scheme.
*
* @return string
*/
public function getName();
}
@@ -0,0 +1,104 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles Base 64 Transfer Encoding in Swift Mailer.
*
* @author Chris Corbyn
*/
class Swift_Mime_ContentEncoder_Base64ContentEncoder extends Swift_Encoder_Base64Encoder implements Swift_Mime_ContentEncoder
{
/**
* Encode stream $in to stream $out.
*
* @param Swift_OutputByteStream $os
* @param Swift_InputByteStream $is
* @param int $firstLineOffset
* @param int $maxLineLength, optional, 0 indicates the default of 76 bytes
*/
public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
{
if (0 >= $maxLineLength || 76 < $maxLineLength) {
$maxLineLength = 76;
}
$remainder = 0;
$base64ReadBufferRemainderBytes = null;
// To reduce memory usage, the output buffer is streamed to the input buffer like so:
// Output Stream => base64encode => wrap line length => Input Stream
// HOWEVER it's important to note that base64_encode() should only be passed whole triplets of data (except for the final chunk of data)
// otherwise it will assume the input data has *ended* and it will incorrectly pad/terminate the base64 data mid-stream.
// We use $base64ReadBufferRemainderBytes to carry over 1-2 "remainder" bytes from the each chunk from OutputStream and pre-pend those onto the
// chunk of bytes read in the next iteration.
// When the OutputStream is empty, we must flush any remainder bytes.
while (true) {
$readBytes = $os->read(8192);
$atEOF = ($readBytes === false);
if ($atEOF) {
$streamTheseBytes = $base64ReadBufferRemainderBytes;
} else {
$streamTheseBytes = $base64ReadBufferRemainderBytes.$readBytes;
}
$base64ReadBufferRemainderBytes = null;
$bytesLength = strlen($streamTheseBytes);
if ($bytesLength === 0) { // no data left to encode
break;
}
// if we're not on the last block of the ouput stream, make sure $streamTheseBytes ends with a complete triplet of data
// and carry over remainder 1-2 bytes to the next loop iteration
if (!$atEOF) {
$excessBytes = $bytesLength % 3;
if ($excessBytes !== 0) {
$base64ReadBufferRemainderBytes = substr($streamTheseBytes, -$excessBytes);
$streamTheseBytes = substr($streamTheseBytes, 0, $bytesLength - $excessBytes);
}
}
$encoded = base64_encode($streamTheseBytes);
$encodedTransformed = '';
$thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset;
while ($thisMaxLineLength < strlen($encoded)) {
$encodedTransformed .= substr($encoded, 0, $thisMaxLineLength)."\r\n";
$firstLineOffset = 0;
$encoded = substr($encoded, $thisMaxLineLength);
$thisMaxLineLength = $maxLineLength;
$remainder = 0;
}
if (0 < $remainingLength = strlen($encoded)) {
$remainder += $remainingLength;
$encodedTransformed .= $encoded;
$encoded = null;
}
$is->write($encodedTransformed);
if ($atEOF) {
break;
}
}
}
/**
* Get the name of this encoding scheme.
* Returns the string 'base64'.
*
* @return string
*/
public function getName()
{
return 'base64';
}
}
@@ -0,0 +1,123 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles Quoted Printable (QP) Transfer Encoding in Swift Mailer using the PHP core function.
*
* @author Lars Strojny
*/
class Swift_Mime_ContentEncoder_NativeQpContentEncoder implements Swift_Mime_ContentEncoder
{
/**
* @var null|string
*/
private $charset;
/**
* @param null|string $charset
*/
public function __construct($charset = null)
{
$this->charset = $charset ? $charset : 'utf-8';
}
/**
* Notify this observer that the entity's charset has changed.
*
* @param string $charset
*/
public function charsetChanged($charset)
{
$this->charset = $charset;
}
/**
* Encode $in to $out.
*
* @param Swift_OutputByteStream $os to read from
* @param Swift_InputByteStream $is to write to
* @param int $firstLineOffset
* @param int $maxLineLength 0 indicates the default length for this encoding
*
* @throws RuntimeException
*/
public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
{
if ($this->charset !== 'utf-8') {
throw new RuntimeException(
sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset));
}
$string = '';
while (false !== $bytes = $os->read(8192)) {
$string .= $bytes;
}
$is->write($this->encodeString($string));
}
/**
* Get the MIME name of this content encoding scheme.
*
* @return string
*/
public function getName()
{
return 'quoted-printable';
}
/**
* Encode a given string to produce an encoded string.
*
* @param string $string
* @param int $firstLineOffset if first line needs to be shorter
* @param int $maxLineLength 0 indicates the default length for this encoding
*
* @throws RuntimeException
*
* @return string
*/
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
{
if ($this->charset !== 'utf-8') {
throw new RuntimeException(
sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset));
}
return $this->_standardize(quoted_printable_encode($string));
}
/**
* Make sure CRLF is correct and HT/SPACE are in valid places.
*
* @param string $string
*
* @return string
*/
protected function _standardize($string)
{
// transform CR or LF to CRLF
$string = preg_replace('~=0D(?!=0A)|(?<!=0D)=0A~', '=0D=0A', $string);
// transform =0D=0A to CRLF
$string = str_replace(array("\t=0D=0A", ' =0D=0A', '=0D=0A'), array("=09\r\n", "=20\r\n", "\r\n"), $string);
switch ($end = ord(substr($string, -1))) {
case 0x09:
$string = substr_replace($string, '=09', -1);
break;
case 0x20:
$string = substr_replace($string, '=20', -1);
break;
}
return $string;
}
}
@@ -0,0 +1,162 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles binary/7/8-bit Transfer Encoding in Swift Mailer.
*
* @author Chris Corbyn
*/
class Swift_Mime_ContentEncoder_PlainContentEncoder implements Swift_Mime_ContentEncoder
{
/**
* The name of this encoding scheme (probably 7bit or 8bit).
*
* @var string
*/
private $_name;
/**
* True if canonical transformations should be done.
*
* @var bool
*/
private $_canonical;
/**
* Creates a new PlainContentEncoder with $name (probably 7bit or 8bit).
*
* @param string $name
* @param bool $canonical If canonicalization transformation should be done.
*/
public function __construct($name, $canonical = false)
{
$this->_name = $name;
$this->_canonical = $canonical;
}
/**
* Encode a given string to produce an encoded string.
*
* @param string $string
* @param int $firstLineOffset ignored
* @param int $maxLineLength - 0 means no wrapping will occur
*
* @return string
*/
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
{
if ($this->_canonical) {
$string = $this->_canonicalize($string);
}
return $this->_safeWordWrap($string, $maxLineLength, "\r\n");
}
/**
* Encode stream $in to stream $out.
*
* @param Swift_OutputByteStream $os
* @param Swift_InputByteStream $is
* @param int $firstLineOffset ignored
* @param int $maxLineLength optional, 0 means no wrapping will occur
*/
public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
{
$leftOver = '';
while (false !== $bytes = $os->read(8192)) {
$toencode = $leftOver.$bytes;
if ($this->_canonical) {
$toencode = $this->_canonicalize($toencode);
}
$wrapped = $this->_safeWordWrap($toencode, $maxLineLength, "\r\n");
$lastLinePos = strrpos($wrapped, "\r\n");
$leftOver = substr($wrapped, $lastLinePos);
$wrapped = substr($wrapped, 0, $lastLinePos);
$is->write($wrapped);
}
if (strlen($leftOver)) {
$is->write($leftOver);
}
}
/**
* Get the name of this encoding scheme.
*
* @return string
*/
public function getName()
{
return $this->_name;
}
/**
* Not used.
*/
public function charsetChanged($charset)
{
}
/**
* A safer (but weaker) wordwrap for unicode.
*
* @param string $string
* @param int $length
* @param string $le
*
* @return string
*/
private function _safeWordwrap($string, $length = 75, $le = "\r\n")
{
if (0 >= $length) {
return $string;
}
$originalLines = explode($le, $string);
$lines = array();
$lineCount = 0;
foreach ($originalLines as $originalLine) {
$lines[] = '';
$currentLine = &$lines[$lineCount++];
//$chunks = preg_split('/(?<=[\ \t,\.!\?\-&\+\/])/', $originalLine);
$chunks = preg_split('/(?<=\s)/', $originalLine);
foreach ($chunks as $chunk) {
if (0 != strlen($currentLine)
&& strlen($currentLine.$chunk) > $length) {
$lines[] = '';
$currentLine = &$lines[$lineCount++];
}
$currentLine .= $chunk;
}
}
return implode("\r\n", $lines);
}
/**
* Canonicalize string input (fix CRLF).
*
* @param string $string
*
* @return string
*/
private function _canonicalize($string)
{
return str_replace(
array("\r\n", "\r", "\n"),
array("\n", "\n", "\r\n"),
$string
);
}
}
@@ -0,0 +1,134 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles Quoted Printable (QP) Transfer Encoding in Swift Mailer.
*
* @author Chris Corbyn
*/
class Swift_Mime_ContentEncoder_QpContentEncoder extends Swift_Encoder_QpEncoder implements Swift_Mime_ContentEncoder
{
protected $_dotEscape;
/**
* Creates a new QpContentEncoder for the given CharacterStream.
*
* @param Swift_CharacterStream $charStream to use for reading characters
* @param Swift_StreamFilter $filter if canonicalization should occur
* @param bool $dotEscape if dot stuffing workaround must be enabled
*/
public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null, $dotEscape = false)
{
$this->_dotEscape = $dotEscape;
parent::__construct($charStream, $filter);
}
public function __sleep()
{
return array('_charStream', '_filter', '_dotEscape');
}
protected function getSafeMapShareId()
{
return get_class($this).($this->_dotEscape ? '.dotEscape' : '');
}
protected function initSafeMap()
{
parent::initSafeMap();
if ($this->_dotEscape) {
/* Encode . as =2e for buggy remote servers */
unset($this->_safeMap[0x2e]);
}
}
/**
* Encode stream $in to stream $out.
*
* QP encoded strings have a maximum line length of 76 characters.
* If the first line needs to be shorter, indicate the difference with
* $firstLineOffset.
*
* @param Swift_OutputByteStream $os output stream
* @param Swift_InputByteStream $is input stream
* @param int $firstLineOffset
* @param int $maxLineLength
*/
public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
{
if ($maxLineLength > 76 || $maxLineLength <= 0) {
$maxLineLength = 76;
}
$thisLineLength = $maxLineLength - $firstLineOffset;
$this->_charStream->flushContents();
$this->_charStream->importByteStream($os);
$currentLine = '';
$prepend = '';
$size = $lineLen = 0;
while (false !== $bytes = $this->_nextSequence()) {
// If we're filtering the input
if (isset($this->_filter)) {
// If we can't filter because we need more bytes
while ($this->_filter->shouldBuffer($bytes)) {
// Then collect bytes into the buffer
if (false === $moreBytes = $this->_nextSequence(1)) {
break;
}
foreach ($moreBytes as $b) {
$bytes[] = $b;
}
}
// And filter them
$bytes = $this->_filter->filter($bytes);
}
$enc = $this->_encodeByteSequence($bytes, $size);
$i = strpos($enc, '=0D=0A');
$newLineLength = $lineLen + ($i === false ? $size : $i);
if ($currentLine && $newLineLength >= $thisLineLength) {
$is->write($prepend.$this->_standardize($currentLine));
$currentLine = '';
$prepend = "=\r\n";
$thisLineLength = $maxLineLength;
$lineLen = 0;
}
$currentLine .= $enc;
if ($i === false) {
$lineLen += $size;
} else {
// 6 is the length of '=0D=0A'.
$lineLen = $size - strrpos($enc, '=0D=0A') - 6;
}
}
if (strlen($currentLine)) {
$is->write($prepend.$this->_standardize($currentLine));
}
}
/**
* Get the name of this encoding scheme.
* Returns the string 'quoted-printable'.
*
* @return string
*/
public function getName()
{
return 'quoted-printable';
}
}
@@ -0,0 +1,98 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Proxy for quoted-printable content encoders.
*
* Switches on the best QP encoder implementation for current charset.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*/
class Swift_Mime_ContentEncoder_QpContentEncoderProxy implements Swift_Mime_ContentEncoder
{
/**
* @var Swift_Mime_ContentEncoder_QpContentEncoder
*/
private $safeEncoder;
/**
* @var Swift_Mime_ContentEncoder_NativeQpContentEncoder
*/
private $nativeEncoder;
/**
* @var null|string
*/
private $charset;
/**
* Constructor.
*
* @param Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder
* @param Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder
* @param string|null $charset
*/
public function __construct(Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder, $charset)
{
$this->safeEncoder = $safeEncoder;
$this->nativeEncoder = $nativeEncoder;
$this->charset = $charset;
}
/**
* Make a deep copy of object.
*/
public function __clone()
{
$this->safeEncoder = clone $this->safeEncoder;
$this->nativeEncoder = clone $this->nativeEncoder;
}
/**
* {@inheritdoc}
*/
public function charsetChanged($charset)
{
$this->charset = $charset;
$this->safeEncoder->charsetChanged($charset);
}
/**
* {@inheritdoc}
*/
public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
{
$this->getEncoder()->encodeByteStream($os, $is, $firstLineOffset, $maxLineLength);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'quoted-printable';
}
/**
* {@inheritdoc}
*/
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
{
return $this->getEncoder()->encodeString($string, $firstLineOffset, $maxLineLength);
}
/**
* @return Swift_Mime_ContentEncoder
*/
private function getEncoder()
{
return 'utf-8' === $this->charset ? $this->nativeEncoder : $this->safeEncoder;
}
}
@@ -0,0 +1,64 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles raw Transfer Encoding in Swift Mailer.
*
*
* @author Sebastiaan Stok <s.stok@rollerscapes.net>
*/
class Swift_Mime_ContentEncoder_RawContentEncoder implements Swift_Mime_ContentEncoder
{
/**
* Encode a given string to produce an encoded string.
*
* @param string $string
* @param int $firstLineOffset ignored
* @param int $maxLineLength ignored
*
* @return string
*/
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
{
return $string;
}
/**
* Encode stream $in to stream $out.
*
* @param Swift_OutputByteStream $in
* @param Swift_InputByteStream $out
* @param int $firstLineOffset ignored
* @param int $maxLineLength ignored
*/
public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
{
while (false !== ($bytes = $os->read(8192))) {
$is->write($bytes);
}
}
/**
* Get the name of this encoding scheme.
*
* @return string
*/
public function getName()
{
return 'raw';
}
/**
* Not used.
*/
public function charsetChanged($charset)
{
}
}
@@ -0,0 +1,45 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An embedded file, in a multipart message.
*
* @author Chris Corbyn
*/
class Swift_Mime_EmbeddedFile extends Swift_Mime_Attachment
{
/**
* Creates a new Attachment with $headers and $encoder.
*
* @param Swift_Mime_HeaderSet $headers
* @param Swift_Mime_ContentEncoder $encoder
* @param Swift_KeyCache $cache
* @param Swift_Mime_Grammar $grammar
* @param array $mimeTypes optional
*/
public function __construct(Swift_Mime_HeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_Mime_Grammar $grammar, $mimeTypes = array())
{
parent::__construct($headers, $encoder, $cache, $grammar, $mimeTypes);
$this->setDisposition('inline');
$this->setId($this->getId());
}
/**
* Get the nesting level of this EmbeddedFile.
*
* Returns {@see LEVEL_RELATED}.
*
* @return int
*/
public function getNestingLevel()
{
return self::LEVEL_RELATED;
}
}
@@ -0,0 +1,24 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Observes changes for a Mime entity's ContentEncoder.
*
* @author Chris Corbyn
*/
interface Swift_Mime_EncodingObserver
{
/**
* Notify this observer that the observed entity's ContentEncoder has changed.
*
* @param Swift_Mime_ContentEncoder $encoder
*/
public function encoderChanged(Swift_Mime_ContentEncoder $encoder);
}
@@ -0,0 +1,176 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Defines the grammar to use for validation, implements the RFC 2822 (and friends) ABNF grammar definitions.
*
* @author Fabien Potencier
* @author Chris Corbyn
*/
class Swift_Mime_Grammar
{
/**
* Special characters used in the syntax which need to be escaped.
*
* @var string[]
*/
private static $_specials = array();
/**
* Tokens defined in RFC 2822 (and some related RFCs).
*
* @var string[]
*/
private static $_grammar = array();
/**
* Initialize some RFC 2822 (and friends) ABNF grammar definitions.
*/
public function __construct()
{
$this->init();
}
public function __wakeup()
{
$this->init();
}
protected function init()
{
if (count(self::$_specials) > 0) {
return;
}
self::$_specials = array(
'(', ')', '<', '>', '[', ']',
':', ';', '@', ',', '.', '"',
);
/*** Refer to RFC 2822 for ABNF grammar ***/
// All basic building blocks
self::$_grammar['NO-WS-CTL'] = '[\x01-\x08\x0B\x0C\x0E-\x19\x7F]';
self::$_grammar['WSP'] = '[ \t]';
self::$_grammar['CRLF'] = '(?:\r\n)';
self::$_grammar['FWS'] = '(?:(?:'.self::$_grammar['WSP'].'*'.
self::$_grammar['CRLF'].')?'.self::$_grammar['WSP'].')';
self::$_grammar['text'] = '[\x00-\x08\x0B\x0C\x0E-\x7F]';
self::$_grammar['quoted-pair'] = '(?:\\\\'.self::$_grammar['text'].')';
self::$_grammar['ctext'] = '(?:'.self::$_grammar['NO-WS-CTL'].
'|[\x21-\x27\x2A-\x5B\x5D-\x7E])';
// Uses recursive PCRE (?1) -- could be a weak point??
self::$_grammar['ccontent'] = '(?:'.self::$_grammar['ctext'].'|'.
self::$_grammar['quoted-pair'].'|(?1))';
self::$_grammar['comment'] = '(\((?:'.self::$_grammar['FWS'].'|'.
self::$_grammar['ccontent'].')*'.self::$_grammar['FWS'].'?\))';
self::$_grammar['CFWS'] = '(?:(?:'.self::$_grammar['FWS'].'?'.
self::$_grammar['comment'].')*(?:(?:'.self::$_grammar['FWS'].'?'.
self::$_grammar['comment'].')|'.self::$_grammar['FWS'].'))';
self::$_grammar['qtext'] = '(?:'.self::$_grammar['NO-WS-CTL'].
'|[\x21\x23-\x5B\x5D-\x7E])';
self::$_grammar['qcontent'] = '(?:'.self::$_grammar['qtext'].'|'.
self::$_grammar['quoted-pair'].')';
self::$_grammar['quoted-string'] = '(?:'.self::$_grammar['CFWS'].'?"'.
'('.self::$_grammar['FWS'].'?'.self::$_grammar['qcontent'].')*'.
self::$_grammar['FWS'].'?"'.self::$_grammar['CFWS'].'?)';
self::$_grammar['atext'] = '[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]';
self::$_grammar['atom'] = '(?:'.self::$_grammar['CFWS'].'?'.
self::$_grammar['atext'].'+'.self::$_grammar['CFWS'].'?)';
self::$_grammar['dot-atom-text'] = '(?:'.self::$_grammar['atext'].'+'.
'(\.'.self::$_grammar['atext'].'+)*)';
self::$_grammar['dot-atom'] = '(?:'.self::$_grammar['CFWS'].'?'.
self::$_grammar['dot-atom-text'].'+'.self::$_grammar['CFWS'].'?)';
self::$_grammar['word'] = '(?:'.self::$_grammar['atom'].'|'.
self::$_grammar['quoted-string'].')';
self::$_grammar['phrase'] = '(?:'.self::$_grammar['word'].'+?)';
self::$_grammar['no-fold-quote'] = '(?:"(?:'.self::$_grammar['qtext'].
'|'.self::$_grammar['quoted-pair'].')*")';
self::$_grammar['dtext'] = '(?:'.self::$_grammar['NO-WS-CTL'].
'|[\x21-\x5A\x5E-\x7E])';
self::$_grammar['no-fold-literal'] = '(?:\[(?:'.self::$_grammar['dtext'].
'|'.self::$_grammar['quoted-pair'].')*\])';
// Message IDs
self::$_grammar['id-left'] = '(?:'.self::$_grammar['dot-atom-text'].'|'.
self::$_grammar['no-fold-quote'].')';
self::$_grammar['id-right'] = '(?:'.self::$_grammar['dot-atom-text'].'|'.
self::$_grammar['no-fold-literal'].')';
// Addresses, mailboxes and paths
self::$_grammar['local-part'] = '(?:'.self::$_grammar['dot-atom'].'|'.
self::$_grammar['quoted-string'].')';
self::$_grammar['dcontent'] = '(?:'.self::$_grammar['dtext'].'|'.
self::$_grammar['quoted-pair'].')';
self::$_grammar['domain-literal'] = '(?:'.self::$_grammar['CFWS'].'?\[('.
self::$_grammar['FWS'].'?'.self::$_grammar['dcontent'].')*?'.
self::$_grammar['FWS'].'?\]'.self::$_grammar['CFWS'].'?)';
self::$_grammar['domain'] = '(?:'.self::$_grammar['dot-atom'].'|'.
self::$_grammar['domain-literal'].')';
self::$_grammar['addr-spec'] = '(?:'.self::$_grammar['local-part'].'@'.
self::$_grammar['domain'].')';
}
/**
* Get the grammar defined for $name token.
*
* @param string $name exactly as written in the RFC
*
* @return string
*/
public function getDefinition($name)
{
if (array_key_exists($name, self::$_grammar)) {
return self::$_grammar[$name];
}
throw new Swift_RfcComplianceException(
"No such grammar '".$name."' defined."
);
}
/**
* Returns the tokens defined in RFC 2822 (and some related RFCs).
*
* @return array
*/
public function getGrammarDefinitions()
{
return self::$_grammar;
}
/**
* Returns the current special characters used in the syntax which need to be escaped.
*
* @return array
*/
public function getSpecials()
{
return self::$_specials;
}
/**
* Escape special characters in a string (convert to quoted-pairs).
*
* @param string $token
* @param string[] $include additional chars to escape
* @param string[] $exclude chars from escaping
*
* @return string
*/
public function escapeSpecials($token, $include = array(), $exclude = array())
{
foreach (array_merge(array('\\'), array_diff(self::$_specials, $exclude), $include) as $char) {
$token = str_replace($char, '\\'.$char, $token);
}
return $token;
}
}
@@ -0,0 +1,93 @@
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A MIME Header.
*
* @author Chris Corbyn
*/
interface Swift_Mime_Header
{
/** Text headers */
const TYPE_TEXT = 2;
/** headers (text + params) */
const TYPE_PARAMETERIZED = 6;
/** Mailbox and address headers */
const TYPE_MAILBOX = 8;
/** Date and time headers */
const TYPE_DATE = 16;
/** Identification headers */
const TYPE_ID = 32;
/** Address path headers */
const TYPE_PATH = 64;
/**
* Get the type of Header that this instance represents.
*
* @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
* @see TYPE_DATE, TYPE_ID, TYPE_PATH
*
* @return int
*/
public function getFieldType();
/**
* Set the model for the field body.
*
* The actual types needed will vary depending upon the type of Header.
*
* @param mixed $model
*/
public function setFieldBodyModel($model);
/**
* Set the charset used when rendering the Header.
*
* @param string $charset
*/
public function setCharset($charset);
/**
* Get the model for the field body.
*
* The return type depends on the specifics of the Header.
*
* @return mixed
*/
public function getFieldBodyModel();
/**
* Get the name of this header (e.g. Subject).
*
* The name is an identifier and as such will be immutable.
*
* @return string
*/
public function getFieldName();
/**
* Get the field body, prepared for folding into a final header value.
*
* @return string
*/
public function getFieldBody();
/**
* Get this Header rendered as a compliant string.
*
* @return string
*/
public function toString();
}

Some files were not shown because too many files have changed in this diff Show More