Initial commit with Symfony 2.1+Vendors

Signed-off-by: Gergely POLONKAI (W00d5t0ck) <polesz@w00d5t0ck.info>
This commit is contained in:
Polonkai Gergely
2012-07-01 09:52:20 +02:00
commit 082a0130c2
5381 changed files with 416709 additions and 0 deletions

165
vendor/swiftmailer/swiftmailer/LICENSE vendored Normal file
View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@@ -0,0 +1 @@
Swift-4.1.9

View File

@@ -0,0 +1,29 @@
{
"name": "swiftmailer/swiftmailer",
"type": "library",
"description": "Swiftmailer, free feature-rich PHP mailer",
"keywords": ["mail","mailer"],
"homepage": "http://swiftmailer.org",
"license": "LGPL",
"authors": [
{
"name": "Chris Corbyn",
"email": ""
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"require": {
"php": ">=5.2.4"
},
"autoload": {
"files": ["lib/swift_required.php"]
},
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
}
}

View File

@@ -0,0 +1,742 @@
Message Headers
===============
Sometimes you'll want to add your own headers to a message or modify/remove
headers that are already present. You work with the message's HeaderSet to do
this.
Header Basics
-------------
All MIME entities in Swift Mailer -- including the message itself --
store their headers in a single object called a HeaderSet. This HeaderSet is
retrieved with the ``getHeaders()`` method.
As mentioned in the previous chapter, everything that forms a part of a message
in Swift Mailer is a MIME entity that is represented by an instance of
``Swift_Mime_MimeEntity``. This includes -- most notably -- the message object
itself, attachments, MIME parts and embedded images. Each of these MIME entities
consists of a body and a set of headers that describe the body.
For all of the "standard" headers in these MIME entities, such as the
``Content-Type``, there are named methods for working with them, such as
``setContentType()`` and ``getContentType()``. This is because headers are a
moderately complex area of the library. Each header has a slightly different
required structure that it must meet in order to comply with the standards that
govern email (and that are checked by spam blockers etc).
You fetch the HeaderSet from a MIME entity like so:
.. code-block:: php
$message = Swift_Message::newInstance();
// Fetch the HeaderSet from a Message object
$headers = $message->getHeaders();
$attachment = Swift_Attachment::fromPath('document.pdf');
// Fetch the HeaderSet from an attachment object
$headers = $attachment->getHeaders();
The job of the HeaderSet is to contain and manage instances of Header objects.
Depending upon the MIME entity the HeaderSet came from, the contents of the
HeaderSet will be different, since an attachment for example has a different
set of headers to those in a message.
You can find out what the HeaderSet contains with a quick loop, dumping out
the names of the headers:
.. code-block:: php
foreach ($headers->getAll() as $header) {
printf("%s<br />\n", $header->getFieldName());
}
/*
Content-Transfer-Encoding
Content-Type
MIME-Version
Date
Message-ID
From
Subject
To
*/
You can also dump out the rendered HeaderSet by calling its ``toString()``
method:
.. code-block:: php
echo $headers->toString();
/*
Message-ID: <1234869991.499a9ee7f1d5e@swift.generated>
Date: Tue, 17 Feb 2009 22:26:31 +1100
Subject: Awesome subject!
From: sender@example.org
To: recipient@example.org
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
*/
Where the complexity comes in is when you want to modify an existing header.
This complexity comes from the fact that each header can be of a slightly
different type (such as a Date header, or a header that contains email
addresses, or a header that has key-value parameters on it!). Each header in the
HeaderSet is an instance of ``Swift_Mime_Header``. They all have common
functionality, but knowing exactly what type of header you're working with will
allow you a little more control.
You can determine the type of header by comparing the return value of its
``getFieldType()`` method with the constants ``TYPE_TEXT``,
``TYPE_PARAMETERIZED``, ``TYPE_DATE``, ``TYPE_MAILBOX``, ``TYPE_ID`` and
``TYPE_PATH`` which are defined in ``Swift_Mime_Header``.
.. code-block:: php
foreach ($headers->getAll() as $header) {
switch ($header->getFieldType()) {
case Swift_Mime_Header::TYPE_TEXT: $type = 'text';
break;
case Swift_Mime_Header::TYPE_PARAMETERIZED: $type = 'parameterized';
break;
case Swift_Mime_Header::TYPE_MAILBOX: $type = 'mailbox';
break;
case Swift_Mime_Header::TYPE_DATE: $type = 'date';
break;
case Swift_Mime_Header::TYPE_ID: $type = 'ID';
break;
case Swift_Mime_Header::TYPE_PATH: $type = 'path';
break;
}
printf("%s: is a %s header<br />\n", $header->getFieldName(), $type);
}
/*
Content-Transfer-Encoding: is a text header
Content-Type: is a parameterized header
MIME-Version: is a text header
Date: is a date header
Message-ID: is a ID header
From: is a mailbox header
Subject: is a text header
To: is a mailbox header
*/
Headers can be removed from the set, modified within the set, or added to the
set.
The following sections show you how to work with the HeaderSet and explain the
details of each implementation of ``Swift_Mime_Header`` that may
exist within the HeaderSet.
Header Types
------------
Because all headers are modeled on different data (dates, addresses, text!)
there are different types of Header in Swift Mailer. Swift Mailer attempts to
categorize all possible MIME headers into more general groups, defined by a
small number of classes.
Text Headers
~~~~~~~~~~~~
Text headers are the simplest type of Header. They contain textual information
with no special information included within it -- for example the Subject
header in a message.
There's nothing particularly interesting about a text header, though it is
probably the one you'd opt to use if you need to add a custom header to a
message. It represents text just like you'd think it does. If the text
contains characters that are not permitted in a message header (such as new
lines, or non-ascii characters) then the header takes care of encoding the
text so that it can be used.
No header -- including text headers -- in Swift Mailer is vulnerable to
header-injection attacks. Swift Mailer breaks any attempt at header injection by
encoding the dangerous data into a non-dangerous form.
It's easy to add a new text header to a HeaderSet. You do this by calling the
HeaderSet's ``addTextHeader()`` method.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addTextHeader('Your-Header-Name', 'the header value');
Changing the value of an existing text header is done by calling it's
``setValue()`` method.
.. code-block:: php
$subject = $message->getHeaders()->get('Subject');
$subject->setValue('new subject');
When output via ``toString()``, a text header produces something like the
following:
.. code-block:: php
$subject = $message->getHeaders()->get('Subject');
$subject->setValue('amazing subject line');
echo $subject->toString();
/*
Subject: amazing subject line
*/
If the header contains any characters that are outside of the US-ASCII range
however, they will be encoded. This is nothing to be concerned about since
mail clients will decode them back.
.. code-block:: php
$subject = $message->getHeaders()->get('Subject');
$subject->setValue('contains dash');
echo $subject->toString();
/*
Subject: contains =?utf-8?Q?=E2=80=93?= dash
*/
Parameterized Headers
~~~~~~~~~~~~~~~~~~~~~
Parameterized headers are text headers that contain key-value parameters
following the textual content. The Content-Type header of a message is a
parameterized header since it contains charset information after the content
type.
The parameterized header type is a special type of text header. It extends the
text header by allowing additional information to follow it. All of the methods
from text headers are available in addition to the methods described here.
Adding a parameterized header to a HeaderSet is done by using the
``addParameterizedHeader()`` method which takes a text value like
``addTextHeader()`` but it also accepts an associative array of
key-value parameters.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addParameterizedHeader(
'Header-Name', 'header value',
array('foo' => 'bar')
);
To change the text value of the header, call it's ``setValue()`` method just as
you do with text headers.
To change the parameters in the header, call the header's ``setParameters()``
method or the ``setParameter()`` method (note the pluralization).
.. code-block:: php
$type = $message->getHeaders()->get('Content-Type');
// setParameters() takes an associative array
$type->setParameters(array(
'name' => 'file.txt',
'charset' => 'iso-8859-1'
));
// setParameter() takes two args for $key and $value
$type->setParameter('charset', 'iso-8859-1');
When output via ``toString()``, a parameterized header produces something like
the following:
.. code-block:: php
$type = $message->getHeaders()->get('Content-Type');
$type->setValue('text/html');
$type->setParameter('charset', 'utf-8');
echo $type->toString();
/*
Content-Type: text/html; charset=utf-8
*/
If the header contains any characters that are outside of the US-ASCII range
however, they will be encoded, just like they are for text headers. This is
nothing to be concerned about since mail clients will decode them back.
Likewise, if the parameters contain any non-ascii characters they will be
encoded so that they can be transmitted safely.
.. code-block:: php
$attachment = Swift_Attachment::newInstance();
$disp = $attachment->getHeaders()->get('Content-Disposition');
$disp->setValue('attachment');
$disp->setParameter('filename', 'reportmay.pdf');
echo $disp->toString();
/*
Content-Disposition: attachment; filename*=utf-8''report%E2%80%93may.pdf
*/
Date Headers
~~~~~~~~~~~~
Date headers contains an RFC 2822 formatted date (i.e. what PHP's ``date('r')``
returns). They are used anywhere a date or time is needed to be presented as a
message header.
The data on which a date header is modeled is simply a UNIX timestamp such as
that returned by ``time()`` or ``strtotime()``. The timestamp is used to create
a correctly structured RFC 2822 formatted date such as
``Tue, 17 Feb 2009 22:26:31 +1100``.
The obvious place this header type is used is in the ``Date:`` header of the
message itself.
It's easy to add a new date header to a HeaderSet. You do this by calling
the HeaderSet's ``addDateHeader()`` method.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addDateHeader('Your-Header-Name', strtotime('3 days ago'));
Changing the value of an existing date header is done by calling it's
``setTimestamp()`` method.
.. code-block:: php
$date = $message->getHeaders()->get('Date');
$date->setTimestamp(time());
When output via ``toString()``, a date header produces something like the
following:
.. code-block:: php
$date = $message->getHeaders()->get('Date');
echo $date->toString();
/*
Date: Wed, 18 Feb 2009 13:35:02 +1100
*/
Mailbox (e-mail address) Headers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mailbox headers contain one or more email addresses, possibly with
personalized names attached to them. The data on which they are modeled is
represented by an associative array of email addresses and names.
Mailbox headers are probably the most complex header type to understand in
Swift Mailer because they accept their input as an array which can take various
forms, as described in the previous chapter.
All of the headers that contain e-mail addresses in a message -- with the
exception of ``Return-Path:`` which has a stricter syntax -- use this header
type. That is, ``To:``, ``From:`` etc.
You add a new mailbox header to a HeaderSet by calling the HeaderSet's
``addMailboxHeader()`` method.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addMailboxHeader('Your-Header-Name', array(
'person1@example.org' => 'Person Name One',
'person2@example.org',
'person3@example.org',
'person4@example.org' => 'Another named person'
));
Changing the value of an existing mailbox header is done by calling it's
``setNameAddresses()`` method.
.. code-block:: php
$to = $message->getHeaders()->get('To');
$to->setNameAddresses(array(
'joe@example.org' => 'Joe Bloggs',
'john@example.org' => 'John Doe',
'no-name@example.org'
));
If you don't wish to concern yourself with the complicated accepted input
formats accepted by ``setNameAddresses()`` as described in the previous chapter
and you only want to set one or more addresses (not names) then you can just
use the ``setAddresses()`` method instead.
.. code-block:: php
$to = $message->getHeaders()->get('To');
$to->setAddresses(array(
'joe@example.org',
'john@example.org',
'no-name@example.org'
));
.. note::
Both methods will accept the above input format in practice.
If all you want to do is set a single address in the header, you can use a
string as the input parameter to ``setAddresses()`` and/or
``setNameAddresses()``.
.. code-block:: php
$to = $message->getHeaders()->get('To');
$to->setAddresses('joe-bloggs@example.org');
When output via ``toString()``, a mailbox header produces something like the
following:
.. code-block:: php
$to = $message->getHeaders()->get('To');
$to->setNameAddresses(array(
'person1@example.org' => 'Name of Person',
'person2@example.org',
'person3@example.org' => 'Another Person'
));
echo $to->toString();
/*
To: Name of Person <person1@example.org>, person2@example.org, Another Person
<person3@example.org>
*/
ID Headers
~~~~~~~~~~
ID headers contain identifiers for the entity (or the message). The most
notable ID header is the Message-ID header on the message itself.
An ID that exists inside an ID header looks more-or-less less like an email
address. For example, ``<![CDATA[<1234955437.499becad62ec2@example.org>]]>``.
The part to the left of the @ sign is usually unique, based on the current time
and some random factor. The part on the right is usually a domain name.
Any ID passed the an ID header's ``setId()`` method absolutely MUST conform to
this structure, otherwise you'll get an Exception thrown at you by Swift Mailer
(a ``Swift_RfcComplianceException``). This is to ensure that the generated
email complies with relevant RFC documents and therefore is less likely to be
blocked as spam.
It's easy to add a new ID header to a HeaderSet. You do this by calling
the HeaderSet's ``addIdHeader()`` method.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addIdHeader('Your-Header-Name', '123456.unqiue@example.org');
Changing the value of an existing date header is done by calling its
``setId()`` method.
.. code-block:: php
$msgId = $message->getHeaders()->get('Message-ID');
$msgId->setId(time() . '.' . uniqid('thing') . '@example.org');
When output via ``toString()``, an ID header produces something like the
following:
.. code-block:: php
$msgId = $message->getHeaders()->get('Message-ID');
echo $msgId->toString();
/*
Message-ID: <1234955437.499becad62ec2@example.org>
*/
Path Headers
~~~~~~~~~~~~
Path headers are like very-restricted mailbox headers. They contain a single
email address with no associated name. The Return-Path header of a message is
a path header.
You add a new path header to a HeaderSet by calling the HeaderSet's
``addPathHeader()`` method.
.. code-block:: php
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addPathHeader('Your-Header-Name', 'person@example.org');
Changing the value of an existing path header is done by calling its
``setAddress()`` method.
.. code-block:: php
$return = $message->getHeaders()->get('Return-Path');
$return->setAddress('my-address@example.org');
When output via ``toString()``, a path header produces something like the
following:
.. code-block:: php
$return = $message->getHeaders()->get('Return-Path');
$return->setAddress('person@example.org');
echo $return->toString();
/*
Return-Path: <person@example.org>
*/
Header Operations
-----------------
Working with the headers in a message involves knowing how to use the methods
on the HeaderSet and on the individual Headers within the HeaderSet.
Adding new Headers
~~~~~~~~~~~~~~~~~~
New headers can be added to the HeaderSet by using one of the provided
``add..Header()`` methods.
To add a header to a MIME entity (such as the message):
Get the HeaderSet from the entity by via its ``getHeaders()`` method.
* Add the header to the HeaderSet by calling one of the ``add..Header()``
methods.
The added header will appear in the message when it is sent.
.. code-block:: php
// Adding a custom header to a message
$message = Swift_Message::newInstance();
$headers = $message->getHeaders();
$headers->addTextHeader('X-Mine', 'something here');
// Adding a custom header to an attachment
$attachment = Swift_Attachment::fromPath('/path/to/doc.pdf');
$attachment->getHeaders()->addDateHeader('X-Created-Time', time());
Retrieving Headers
~~~~~~~~~~~~~~~~~~
Headers are retrieved through the HeaderSet's ``get()`` and ``getAll()``
methods.
To get a header, or several headers from a MIME entity:
* Get the HeaderSet from the entity by via its ``getHeaders()`` method.
* Get the header(s) from the HeaderSet by calling either ``get()`` or
``getAll()``.
When using ``get()`` a single header is returned that matches the name (case
insensitive) that is passed to it. When using ``getAll()`` with a header name,
an array of headers with that name are returned. Calling ``getAll()`` with no
arguments returns an array of all headers present in the entity.
.. note::
It's valid for some headers to appear more than once in a message (e.g.
the Received header). For this reason ``getAll()`` exists to fetch all
headers with a specified name. In addition, ``get()`` accepts an optional
numerical index, starting from zero to specify which header you want more
specifically.
.. note::
If you want to modify the contents of the header and you don't know for
sure what type of header it is then you may need to check the type by
calling its ``getFieldType()`` method.
.. code-block:: php
$headers = $message->getHeaders();
// Get the To: header
$toHeader = $headers->get('To');
// Get all headers named "X-Foo"
$fooHeaders = $headers->getAll('X-Foo');
// Get the second header named "X-Foo"
$foo = $headers->get('X-Foo', 1);
// Get all headers that are present
$all = $headers->getAll();
Check if a Header Exists
~~~~~~~~~~~~~~~~~~~~~~~~
You can check if a named header is present in a HeaderSet by calling its
``has()`` method.
To check if a header exists:
* Get the HeaderSet from the entity by via its ``getHeaders()`` method.
* Call the HeaderSet's ``has()`` method specifying the header you're looking
for.
If the header exists, ``true`` will be returned or ``false`` if not.
.. note::
It's valid for some headers to appear more than once in a message (e.g.
the Received header). For this reason ``has()`` accepts an optional
numerical index, starting from zero to specify which header you want to
check more specifically.
.. code-block:: php
$headers = $message->getHeaders();
// Check if the To: header exists
if ($headers->has('To')) {
echo 'To: exists';
}
// Check if an X-Foo header exists twice (i.e. check for the 2nd one)
if ($headers->has('X-Foo', 1)) {
echo 'Second X-Foo header exists';
}
Removing Headers
~~~~~~~~~~~~~~~~
Removing a Header from the HeaderSet is done by calling the HeaderSet's
``remove()`` or ``removeAll()`` methods.
To remove an existing header:
* Get the HeaderSet from the entity by via its ``getHeaders()`` method.
* Call the HeaderSet's ``remove()`` or ``removeAll()`` methods specifying the
header you want to remove.
When calling ``remove()`` a single header will be removed. When calling
``removeAll()`` all headers with the given name will be removed. If no headers
exist with the given name, no errors will occur.
.. note::
It's valid for some headers to appear more than once in a message (e.g.
the Received header). For this reason ``remove()`` accepts an optional
numerical index, starting from zero to specify which header you want to
check more specifically. For the same reason, ``removeAll()`` exists to
remove all headers that have the given name.
.. code-block:: php
$headers = $message->getHeaders();
// Remove the Subject: header
$headers->remove('Subject');
// Remove all X-Foo headers
$headers->removeAll('X-Foo');
// Remove only the second X-Foo header
$headers->remove('X-Foo', 1);
Modifying a Header's Content
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To change a Header's content you should know what type of header it is and then
call it's appropriate setter method. All headers also have a
``setFieldBodyModel()`` method that accepts a mixed parameter and delegates to
the correct setter.
To modify an existing header:
* Get the HeaderSet from the entity by via its ``getHeaders()`` method.
* Get the Header by using the HeaderSet's ``get()``.
* Call the Header's appropriate setter method or call the header's
``setFieldBodyModel()`` method.
The header will be updated inside the HeaderSet and the changes will be seen
when the message is sent.
.. code-block:: php
$headers = $message->getHeaders();
// Change the Subject: header
$subj = $headers->get('Subject');
$subj->setValue('new subject here');
// Change the To: header
$to = $headers->get('To');
$to->setNameAddresses(array(
'person@example.org' => 'Person',
'thing@example.org'
));
// Using the setFieldBodyModel() just delegates to the correct method
// So here to calls setNameAddresses()
$to->setFieldBodyModel(array(
'person@example.org' => 'Person',
'thing@example.org'
));

View File

@@ -0,0 +1,44 @@
Getting Help
============
There are a number of ways you can get help when using Swift Mailer, depending
upon the nature of your problem. For bug reports and feature requests create a
new ticket in Github. For general advice ask on the Google Group
(swiftmailer).
Submitting Bugs & Feature Requests
----------------------------------
Bugs and feature requests should be posted on Github.
If you post a bug or request a feature in the forum, or on the Google Group
you will most likely be asked to create a ticket in `Github`_ since it is
the simply not feasible to manage such requests from a number of a different
sources.
When you go to Github you will be asked to create a username and password
before you can create a ticket. This is free and takes very little time.
When you create your ticket, do not assign it to any milestones. A developer
will assess your ticket and re-assign it as needed.
If your ticket is reporting a bug present in the current version, which was
not present in the previous version please include the tag "regression" in
your ticket.
Github will update you when work is performed on your ticket.
Ask on the Google Group
-----------------------
You can seek advice at Google Groups, within the "swiftmailer" `group`_.
You can post messages to this group if you want help, or there's something you
wish to discuss with the developers and with other users.
This is probably the fastest way to get help since it is primarily email-based
for most users, though bug reports should not be posted here since they may
not be resolved.
.. _`Github`: https://github.com/swiftmailer/swiftmailer/issues
.. _`group`: http://groups.google.com/group/swiftmailer

View File

@@ -0,0 +1,30 @@
Including Swift Mailer (Autoloading)
====================================
Swift Mailer uses an autoloader so the only file you need to include is the
``lib/swift_required.php`` file.
To use Swift Mailer's autoloader:
* Put Swift Mailer somewhere accessible to your PHP scripts (this does not
need to be in the web root).
* Include, or require the ``lib/swift_required.php`` file.
* Follow the remainder of the documentation for using the available
components.
.. note::
While Swift Mailer's autoloader is designed to play nicely with other
autoloaders, sometimes you may have a need to avoid using Swift Mailer's
autoloader and use your own instead. Include the ``swift_init.php``
instead of the ``swift_required.php`` if you need to do this. The very
minimum include is the ``swift_init.php`` file since Swift Mailer will not
work without the dependency injection this file sets up:
.. code-block:: php
require_once '/path/to/swift-mailer/lib/swift_required.php';
/* rest of code goes here */

View File

@@ -0,0 +1,15 @@
Swiftmailer
===========
.. toctree::
:maxdepth: 2
introduction
overview
installing
help-resources
including-the-files
messages
headers
sending
plugins

View File

@@ -0,0 +1,201 @@
Installing the Library
======================
Installing Swift Mailer is trivial. Usually it's just a case of uploading the
extracted source files to your web server.
Installing from PEAR
--------------------
If you want to install Swift Mailer globally on your machine, the easiest
installation method is using the PEAR channel.
To install the Swift Mailer PEAR package:
* Run the command ``pear channel-discover pear.swiftmailer.org``.
* Then, run the command ``pear install swift/swift``.
Installing from a Package
-------------------------
Most users will download a package from the Swift Mailer website and install
Swift Mailer using this.
If you downloaded Swift Mailer as a ``.tar.gz`` or
``.zip`` file installation is as simple as extracting the archive
and uploading it to your web server.
Extracting the Library
~~~~~~~~~~~~~~~~~~~~~~
You extract the archive by using your favorite unarchiving tool such as
``tar`` or 7-Zip.
You will need to have access to a program that can open uncompress the
archive. On Windows computers, 7-Zip will work. On Mac and Linux systems you
can use ``tar`` on the command line.
To extract your downloaded package:
* Use the "extract" facility of your archiving software.
The source code will be placed into a directory with the same name as the
archive (e.g. Swift-4.0.0-b1).
The following example shows the process on Mac OS X and Linux systems using
the ``tar`` command.
.. code-block:: bash
$ ls
Swift-4.0.0-dev.tar.gz
$ tar xvzf Swift-4.0.0-dev.tar.gz
Swift-4.0.0-dev/
Swift-4.0.0-dev/lib/
Swift-4.0.0-dev/lib/classes/
Swift-4.0.0-dev/lib/classes/Swift/
Swift-4.0.0-dev/lib/classes/Swift/ByteStream/
Swift-4.0.0-dev/lib/classes/Swift/CharacterReader/
Swift-4.0.0-dev/lib/classes/Swift/CharacterReaderFactory/
Swift-4.0.0-dev/lib/classes/Swift/CharacterStream/
Swift-4.0.0-dev/lib/classes/Swift/Encoder/
... etc etc ...
Swift-4.0.0-dev/tests/unit/Swift/Transport/LoadBalancedTransportTest.php
Swift-4.0.0-dev/tests/unit/Swift/Transport/SendmailTransportTest.php
Swift-4.0.0-dev/tests/unit/Swift/Transport/StreamBufferTest.php
$ cd Swift-4.0.0-dev
$ ls
CHANGES LICENSE.GPL LICENSE.LGPL README VERSION examples lib test-suite tests
$
Installing from Git
-------------------
It's possible to download and install Swift Mailer directly from github.com if
you want to keep up-to-date with ease.
Swift Mailer's source code is kept in a git repository at github.com so you
can get the source directly from the repository.
.. note::
You do not need to have git installed to use Swift Mailer from github. If
you don't have git installed, go to `github`_ and click the "Download"
button.
Cloning the Repository
~~~~~~~~~~~~~~~~~~~~~~
The repository can be cloned from git://github.com/swiftmailer/swiftmailer.git
using the ``git clone`` command.
You will need to have ``git`` installed before you can use the
``git clone`` command.
To clone the repository:
* Open your favorite terminal environment (command line).
* Move to the directory you want to clone to.
* Run the command ``git clone git://github.com/swiftmailer/swiftmailer.git
swiftmailer``.
The source code will be downloaded into a directory called "swiftmailer".
The example shows the process on a UNIX-like system such as Linux, BSD or Mac
OS X.
.. code-block:: bash
$ cd source_code/
$ git clone git://github.com/swiftmailer/swiftmailer.git swiftmailer
Initialized empty Git repository in /Users/chris/source_code/swiftmailer/.git/
remote: Counting objects: 6815, done.
remote: Compressing objects: 100% (2761/2761), done.
remote: Total 6815 (delta 3641), reused 6326 (delta 3286)
Receiving objects: 100% (6815/6815), 4.35 MiB | 162 KiB/s, done.
Resolving deltas: 100% (3641/3641), done.
Checking out files: 100% (1847/1847), done.
$ cd swiftmailer/
$ ls
CHANGES LICENSE.LGPL README.git VERSION docs lib test-suite util
LICENSE.GPL README TODO build.xml examples notes tests
$
Uploading to your Host
----------------------
You only need to upload the "lib/" directory to your web host for production
use. All other files and directories are support files not needed in
production.
You will need FTP, ``rsync`` or similar software installed in order to upload
the "lib/" directory to your web host.
To upload Swift Mailer:
* Open your FTP program, or a command line if you prefer rsync/scp.
* Upload the "lib/" directory to your hosting account.
The files needed to use Swift Mailer should now be accessible to PHP on your
host.
The following example shows show you can upload the files using
``rsync`` on Linux or OS X.
.. note::
You do not need to place the files inside your web root. They only need to
be in a place where your PHP scripts can "include" them.
.. code-block:: bash
$ rsync -rvz lib d11wtq@swiftmailer.org:swiftmailer
building file list ... done
created directory swiftmailer
lib/
lib/mime_types.php
lib/preferences.php
lib/swift_required.php
lib/classes/
lib/classes/Swift/
lib/classes/Swift/Attachment.php
lib/classes/Swift/CharacterReader.php
... etc etc ...
lib/dependency_maps/
lib/dependency_maps/cache_deps.php
lib/dependency_maps/mime_deps.php
lib/dependency_maps/transport_deps.php
sent 151692 bytes received 2974 bytes 5836.45 bytes/sec
total size is 401405 speedup is 2.60
$
.. _`github`: http://github.com/swiftmailer/swiftmailer
Troubleshooting
---------------
Swift Mailer does not work when used with function overloading as implemented
by ``mbstring`` (``mbstring.func_overload`` set to ``2``). A workaround is to
temporarily change the internal encoding to ``ASCII`` when sending an email:
.. code-block:: php
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2)
{
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
// Create your message and send it with Swift Mailer
if (isset($mbEncoding))
{
mb_internal_encoding($mbEncoding);
}

View File

@@ -0,0 +1,135 @@
Introduction
============
Swift Mailer is a component-based library for sending e-mails from PHP
applications.
Organization of this Book
-------------------------
This book has been written so that those who need information quickly are able
to find what they need, and those who wish to learn more advanced topics can
read deeper into each chapter.
The book begins with an overview of Swift Mailer, discussing what's included
in the package and preparing you for the remainder of the book.
It is possible to read this user guide just like any other book (from
beginning to end). Each chapter begins with a discussion of the contents it
contains, followed by a short code sample designed to give you a head start.
As you get further into a chapter you will learn more about Swift Mailer's
capabilities, but often you will be able to head directly to the topic you
wish to learn about.
Throughout this book you will be presented with code samples, which most
people should find ample to implement Swift Mailer appropriately in their own
projects. We will also use diagrams where appropriate, and where we believe
readers may find it helpful we will discuss some related theory, including
reference to certain documents you are able to find online.
Code Samples
------------
Code samples presented in this book will be displayed on a different colored
background in a monospaced font. Samples are not to be taken as copy & paste
code snippets.
Code examples are used through the book to clarify what is written in text.
They will sometimes be usable as-is, but they should always be taken as
outline/pseudo code only.
A code sample will look like this::
class AClass
{
...
}
//A Comment
$obj = new AClass($arg1, $arg2, ... );
/* A note about another way of doing something
$obj = AClass::newInstance($arg1, $arg2, ... );
*/
The presence of 3 dots ``...`` in a code sample indicates that we have left
out a chunk of the code for brevity, they are not actually part of the code.
We will often place multi-line comments ``/* ... */`` in the code so that we
can show alternative ways of achieving the same result.
You should read the code examples given and try to understand them. They are
kept concise so that you are not overwhelmed with information.
History of Swift Mailer
-----------------------
Swift Mailer began back in 2005 as a one-class project for sending mail over
SMTP. It has since grown into the flexible component-based library that is in
development today.
Chris Corbyn first posted Swift Mailer on a web forum asking for comments from
other developers. It was never intended as a fully supported open source
project, but members of the forum began to adopt it and make use of it.
Very quickly feature requests were coming for the ability to add attachments
and use SMTP authentication, along with a number of other "obvious" missing
features. Considering the only alternative was PHPMailer it seemed like a good
time to bring some fresh tools to the table. Chris began working towards a
more component based, PHP5-like approach unlike the existing single-class,
legacy PHP4 approach taken by PHPMailer.
Members of the forum offered a lot of advice and critique on the code as he
worked through this project and released versions 2 and 3 of the library in
2005 and 2006, which by then had been broken down into smaller classes
offering more flexibility and supporting plugins. To this day the Swift Mailer
team still receive a lot of feature requests from users both on the forum and
in by email.
Until 2008 Chris was the sole developer of Swift Mailer, but entering 2009 he
gained the support of two experienced developers well-known to him: Paul
Annesley and Christopher Thompson. This has been an extremely welcome change.
As of September 2009, Chris handed over the maintenance of Swift Mailer to
Fabien Potencier.
Now 2009 and in its fourth major version Swift Mailer is more object-oriented
and flexible than ever, both from a usability standpoint and from a
development standpoint.
By no means is Swift Mailer ready to call "finished". There are still many
features that can be added to the library along with the constant refactoring
that happens behind the scenes.
It's a Library!
---------------
Swift Mailer is not an application - it's a library.
To most experienced developers this is probably an obvious point to make, but
it's certainly worth mentioning. Many people often contact us having gotten
the completely wrong end of the stick in terms of what Swift Mailer is
actually for.
It's not an application. It does not have a graphical user interface. It
cannot be opened in your web browser directly.
It's a library (or a framework if you like). It provides a whole lot of
classes that do some very complicated things, so that you don't have to. You
"use" Swift Mailer within an application so that your application can have the
ability to send emails.
The component-based structure of the library means that you are free to
implement it in a number of different ways and that you can pick and choose
what you want to use.
An application on the other hand (such as a blog or a forum) is already "put
together" in a particular way, (usually) provides a graphical user interface
and most likely doesn't offer a great deal of integration with your own
application.
Embrace the structure of the library and use the components it offers to your
advantage. Learning what the components do, rather than blindly copying and
pasting existing code will put you in a great position to build a powerful
application!

View File

@@ -0,0 +1,964 @@
Creating Messages
=================
Creating messages in Swift Mailer is done by making use of the various MIME
entities provided with the library. Complex messages can be quickly created
with very little effort.
Quick Reference for Creating a Message
---------------------------------------
You can think of creating a Message as being similar to the steps you perform
when you click the Compose button in your mail client. You give it a subject,
specify some recipients, add any attachments and write your message.
To create a Message:
* Call the ``newInstance()`` method of ``Swift_Message``.
* Set your sender address (``From:``) with ``setFrom()`` or ``setSender()``.
* Set a subject line with ``setSubject()``.
* Set recipients with ``setTo()``, ``setCc()`` and/or ``setBcc()``.
* Set a body with ``setBody()``.
* Add attachments with ``attach()``.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the message
$message = Swift_Message::newInstance()
// Give the message a subject
->setSubject('Your subject')
// Set the From address with an associative array
->setFrom(array('john@doe.com' => 'John Doe'))
// Set the To addresses with an associative array
->setTo(array('receiver@domain.org', 'other@domain.org' => 'A name'))
// Give it a body
->setBody('Here is the message itself')
// And optionally an alternative body
->addPart('<q>Here is the message itself</q>', 'text/html')
// Optionally add any attachments
->attach(Swift_Attachment::fromPath('my-document.pdf'))
;
Message Basics
--------------
A message is a container for anything you want to send to somebody else. There
are several basic aspects of a message that you should know.
An e-mail message is made up of several relatively simple entities that are
combined in different ways to achieve different results. All of these entities
have the same fundamental outline but serve a different purpose. The Message
itself can be defined as a MIME entity, an Attachment is a MIME entity, all
MIME parts are MIME entities -- and so on!
The basic units of each MIME entity -- be it the Message itself, or an
Attachment -- are its Headers and its body:
.. code-block:: text
Header-Name: A header value
Other-Header: Another value
The body content itself
The Headers of a MIME entity, and its body must conform to some strict
standards defined by various RFC documents. Swift Mailer ensures that these
specifications are followed by using various types of object, including
Encoders and different Header types to generate the entity.
The Structure of a Message
~~~~~~~~~~~~~~~~~~~~~~~~~~
Of all of the MIME entities, a message -- ``Swift_Message``
is the largest and most complex. It has many properties that can be updated
and it can contain other MIME entities -- attachments for example --
nested inside it.
A Message has a lot of different Headers which are there to present
information about the message to the recipients' mail client. Most of these
headers will be familiar to the majority of users, but we'll list the basic
ones. Although it's possible to work directly with the Headers of a Message
(or other MIME entity), the standard Headers have accessor methods provided to
abstract away the complex details for you. For example, although the Date on a
message is written with a strict format, you only need to pass a UNIX
timestamp to ``setDate()``.
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| Header | Description | Accessors |
+===============================+====================================================================================================================================+=============================================+
| ``Message-ID`` | Identifies this message with a unique ID, usually containing the domain name and time generated | ``getId()`` / ``setId()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``Return-Path`` | Specifies where bounces should go (Swift Mailer reads this for other uses) | ``getReturnPath()`` / ``setReturnPath()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``From`` | Specifies the address of the person who the message is from. This can be multiple addresses if multiple people wrote the message. | ``getFrom()`` / ``setFrom()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``Sender`` | Specifies the address of the person who physically sent the message (higher precedence than ``From:``) | ``getSender()`` / ``setSender()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``To`` | Specifies the addresses of the intended recipients | ``getTo()`` / ``setTo()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``Cc`` | Specifies the addresses of recipients who will be copied in on the message | ``getCc()`` / ``setCc()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``Bcc`` | Specifies the addresses of recipients who the message will be blind-copied to. Other recipients will not be aware of these copies. | ``getBcc()`` / ``setBcc()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``Reply-To`` | Specifies the address where replies are sent to | ``getReplyTo()`` / ``setReplyTo()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``Subject`` | Specifies the subject line that is displayed in the recipients' mail client | ``getSubject()`` / ``setSubject()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``Date`` | Specifies the date at which the message was sent | ``getDate()`` / ``setDate()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``Content-Type`` | Specifies the format of the message (usually text/plain or text/html) | ``getContentType()`` / ``setContentType()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
| ``Content-Transfer-Encoding`` | Specifies the encoding scheme in the message | ``getEncoder()`` / ``setEncoder()`` |
+-------------------------------+------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------+
Working with a Message Object
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Although there are a lot of available methods on a message object, you only
need to make use of a small subset of them. Usually you'll use
``setSubject()``, ``setTo()`` and
``setFrom()`` before setting the body of your message with
``setBody()``.
Calling methods is simple. You just call them like functions, but using the
object operator "``<![CDATA[->]]>``" to do so. If you've created
a message object and called it ``$message`` then you'd set a
subject on it like so:
.. code-block:: php
require_once 'lib/swift_required.php';
$message = Swift_Message::newInstance();
$message->setSubject('My subject');
All MIME entities (including a message) have a ``toString()``
method that you can call if you want to take a look at what is going to be
sent. For example, if you ``<![CDATA[echo
$message->toString();]]>`` you would see something like this:
.. code-block:: bash
Message-ID: <1230173678.4952f5eeb1432@swift.generated>
Date: Thu, 25 Dec 2008 13:54:38 +1100
Subject: Example subject
From: Chris Corbyn <chris@w3style.co.uk>
To: Receiver Name <recipient@example.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Here is the message
We'll take a closer look at the methods you use to create your message in the
following sections.
Adding Content to Your Message
------------------------------
Rich content can be added to messages in Swift Mailer with relative ease by
calling methods such as ``setSubject()``, ``setBody()``, ``addPart()`` and
``attach()``.
Setting the Subject Line
~~~~~~~~~~~~~~~~~~~~~~~~
The subject line, displayed in the recipients' mail client can be set with the
``setSubject()`` method, or as a parameter to ``Swift_Message::newInstance()``.
To set the subject of your Message:
* Call the ``setSubject()`` method of the Message, or specify it at the time
you create the message.
.. code-block:: php
// Pass it as a parameter when you create the message
$message = Swift_Message::newInstance('My amazing subject');
// Or set it after like this
$message->setSubject('My amazing subject');
Setting the Body Content
~~~~~~~~~~~~~~~~~~~~~~~~
The body of the message -- seen when the user opens the message --
is specified by calling the ``setBody()`` method. If an alternative body is to
be included ``addPart()`` can be used.
The body of a message is the main part that is read by the user. Often people
want to send a message in HTML format (``text/html``), other
times people want to send in plain text (``text/plain``), or
sometimes people want to send both versions and allow the recipient to chose
how they view the message.
As a rule of thumb, if you're going to send a HTML email, always include a
plain-text equivalent of the same content so that users who prefer to read
plain text can do so.
To set the body of your Message:
* Call the ``setBody()`` method of the Message, or specify it at the time you
create the message.
* Add any alternative bodies with ``addPart()``.
If the recipient's mail client offers preferences for displaying text vs. HTML
then the mail client will present that part to the user where available. In
other cases the mail client will display the "best" part it can - usually HTML
if you've included HTML.
.. code-block:: php
// Pass it as a parameter when you create the message
$message = Swift_Message::newInstance('Subject here', 'My amazing body');
// Or set it after like this
$message->setBody('My <em>amazing</em> body', 'text/html');
// Add alternative parts with addPart()
$message->addPart('My amazing body in plain text', 'text/plain');
Attaching Files
---------------
Attachments are downloadable parts of a message and can be added by calling
the ``attach()`` method on the message. You can add attachments that exist on
disk, or you can create attachments on-the-fly.
Attachments are actually an interesting area of Swift Mailer and something
that could put a lot of power at your fingertips if you grasp the concept
behind the way a message is held together.
Although we refer to files sent over e-mails as "attachments" -- because
they're attached to the message -- lots of other parts of the message are
actually "attached" even if we don't refer to these parts as attachments.
File attachments are created by the ``Swift_Attachment`` class
and then attached to the message via the ``attach()`` method on
it. For all of the "every day" MIME types such as all image formats, word
documents, PDFs and spreadsheets you don't need to explicitly set the
content-type of the attachment, though it would do no harm to do so. For less
common formats you should set the content-type -- which we'll cover in a
moment.
Attaching Existing Files
~~~~~~~~~~~~~~~~~~~~~~~~
Files that already exist, either on disk or at a URL can be attached to a
message with just one line of code, using ``Swift_Attachment::fromPath()``.
You can attach files that exist locally, or if your PHP installation has
``allow_url_fopen`` turned on you can attach files from other
websites.
To attach an existing file:
* Create an attachment with ``Swift_Attachment::fromPath()``.
* Add the attachment to the message with ``attach()``.
The attachment will be presented to the recipient as a downloadable file with
the same filename as the one you attached.
.. code-block:: php
// Create the attachment
// * Note that you can technically leave the content-type parameter out
$attachment = Swift_Attachment::fromPath('/path/to/image.jpg', 'image/jpeg');
// Attach it to the message
$message->attach($attachment);
// The two statements above could be written in one line instead
$message->attach(Swift_Attachment::fromPath('/path/to/image.jpg'));
// You can attach files from a URL if allow_url_fopen is on in php.ini
$message->attach(Swift_Attachment::fromPath('http://site.tld/logo.png'));
Setting the Filename
~~~~~~~~~~~~~~~~~~~~
Usually you don't need to explicitly set the filename of an attachment because
the name of the attached file will be used by default, but if you want to set
the filename you use the ``setFilename()`` method of the Attachment.
To change the filename of an attachment:
* Call its ``setFilename()`` method.
The attachment will be attached in the normal way, but meta-data sent inside
the email will rename the file to something else.
.. code-block:: php
// Create the attachment and call its setFilename() method
$attachment = Swift_Attachment::fromPath('/path/to/image.jpg')
->setFilename('cool.jpg');
// Because there's a fluid interface, you can do this in one statement
$message->attach(
Swift_Attachment::fromPath('/path/to/image.jpg')->setFilename('cool.jpg')
);
Attaching Dynamic Content
~~~~~~~~~~~~~~~~~~~~~~~~~
Files that are generated at runtime, such as PDF documents or images created
via GD can be attached directly to a message without writing them out to disk.
Use the standard ``Swift_Attachment::newInstance()`` method.
To attach dynamically created content:
* Create your content as you normally would.
* Create an attachment with ``Swift_Attachment::newInstance()``, specifying
the source data of your content along with a name and the content-type.
* Add the attachment to the message with ``attach()``.
The attachment will be presented to the recipient as a downloadable file
with the filename and content-type you specify.
.. note::
If you would usually write the file to disk anyway you should just attach
it with ``Swift_Attachment::fromPath()`` since this will use less memory:
.. code-block:: php
// Create your file contents in the normal way, but don't write them to disk
$data = create_my_pdf_data();
// Create the attachment with your data
$attachment = Swift_Attachment::newInstance($data, 'my-file.pdf', 'application/pdf');
// Attach it to the message
$message->attach($attachment);
// You can alternatively use method chaining to build the attachment
$attachment = Swift_Attachment::newInstance()
->setFilename('my-file.pdf')
->setContentType('application/pdf')
->setBody($data)
;
Changing the Disposition
~~~~~~~~~~~~~~~~~~~~~~~~
Attachments just appear as files that can be saved to the Desktop if desired.
You can make attachment appear inline where possible by using the
``setDisposition()`` method of an attachment.
To make an attachment appear inline:
* Call its ``setDisposition()`` method.
The attachment will be displayed within the email viewing window if the mail
client knows how to display it.
.. note::
If you try to create an inline attachment for a non-displayable file type
such as a ZIP file, the mail client should just present the attachment as
normal:
.. code-block:: php
// Create the attachment and call its setDisposition() method
$attachment = Swift_Attachment::fromPath('/path/to/image.jpg')
->setDisposition('inline');
// Because there's a fluid interface, you can do this in one statement
$message->attach(
Swift_Attachment::fromPath('/path/to/image.jpg')->setDisposition('inline')
);
Embedding Inline Media Files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Often people want to include an image or other content inline with a HTML
message. It's easy to do this with HTML linking to remote resources, but this
approach is usually blocked by mail clients. Swift Mailer allows you to embed
your media directly into the message.
Mail clients usually block downloads from remote resources because this
technique was often abused as a mean of tracking who opened an email. If
you're sending a HTML email and you want to include an image in the message
another approach you can take is to embed the image directly.
Swift Mailer makes embedding files into messages extremely streamlined. You
embed a file by calling the ``embed()`` method of the message,
which returns a value you can use in a ``src`` or
``href`` attribute in your HTML.
Just like with attachments, it's possible to embed dynamically generated
content without having an existing file available.
The embedded files are sent in the email as a special type of attachment that
has a unique ID used to reference them within your HTML attributes. On mail
clients that do not support embedded files they may appear as attachments.
Although this is commonly done for images, in theory it will work for any
displayable (or playable) media type. Support for other media types (such as
video) is dependent on the mail client however.
Embedding Existing Files
........................
Files that already exist, either on disk or at a URL can be embedded in a
message with just one line of code, using ``Swift_EmbeddedFile::fromPath()``.
You can embed files that exist locally, or if your PHP installation has
``allow_url_fopen`` turned on you can embed files from other websites.
To embed an existing file:
* Create a message object with ``Swift_Message::newInstance()``.
* Set the body as HTML, and embed a file at the correct point in the message with ``embed()``.
The file will be displayed with the message inline with the HTML wherever its ID
is used as a ``src`` attribute.
.. note::
``Swift_Image`` and ``Swift_EmbeddedFile`` are just aliases of one
another. ``Swift_Image`` exists for semantic purposes.
.. note::
You can embed files in two stages if you prefer. Just capture the return
value of ``embed()`` in a variable and use that as the ``src`` attribute.
.. code-block:: php
// Create the message
$message = Swift_Message::newInstance('My subject');
// Set the body
$message->setBody(
'<html>' .
' <head></head>' .
' <body>' .
' Here is an image <img src="' . // Embed the file
$message->embed(Swift_Image::fromPath('image.png')) .
'" alt="Image" />' .
' Rest of message' .
' </body>' .
'</html>',
'text/html' // Mark the content-type as HTML
);
// You can embed files from a URL if allow_url_fopen is on in php.ini
$message->setBody(
'<html>' .
' <head></head>' .
' <body>' .
' Here is an image <img src="' .
$message->embed(Swift_Image::fromPath('http://site.tld/logo.png')) .
'" alt="Image" />' .
' Rest of message' .
' </body>' .
'</html>',
'text/html'
);
// If placing the embed() code inline becomes cumbersome
// it's easy to do this in two steps
$cid = $message->embed(Swift_Image::fromPath('image.png'));
$message->setBody(
'<html>' .
' <head></head>' .
' <body>' .
' Here is an image <img src="' . $cid . '" alt="Image" />' .
' Rest of message' .
' </body>' .
'</html>',
'text/html' // Mark the content-type as HTML
);
Embedding Dynamic Content
.........................
Images that are generated at runtime, such as images created via GD can be
embedded directly to a message without writing them out to disk. Use the
standard ``Swift_Image::newInstance()`` method.
To embed dynamically created content:
* Create a message object with ``Swift_Message::newInstance()``.
* Set the body as HTML, and embed a file at the correct point in the message
with ``embed()``. You will need to specify a filename and a content-type.
The file will be displayed with the message inline with the HTML wherever its ID
is used as a ``src`` attribute.
.. note::
``Swift_Image`` and ``Swift_EmbeddedFile`` are just aliases of one
another. ``Swift_Image`` exists for semantic purposes.
.. note::
You can embed files in two stages if you prefer. Just capture the return
value of ``embed()`` in a variable and use that as the ``src`` attribute.
.. code-block:: php
// Create your file contents in the normal way, but don't write them to disk
$img_data = create_my_image_data();
//Create the message
$message = Swift_Message::newInstance('My subject');
//Set the body
$message->setBody(
'<html>' .
' <head></head>' .
' <body>' .
' Here is an image <img src="' . // Embed the file
$message->embed(Swift_Image::newInstance($img_data, 'image.jpg', 'image/jpeg')) .
'" alt="Image" />' .
' Rest of message' .
' </body>' .
'</html>',
'text/html' // Mark the content-type as HTML
);
// If placing the embed() code inline becomes cumbersome
// it's easy to do this in two steps
$cid = $message->embed(Swift_Image::newInstance($img_data, 'image.jpg', 'image/jpeg'));
$message->setBody(
'<html>' .
' <head></head>' .
' <body>' .
' Here is an image <img src="' . $cid . '" alt="Image" />' .
' Rest of message' .
' </body>' .
'</html>',
'text/html' // Mark the content-type as HTML
);
Adding Recipients to Your Message
---------------------------------
Recipients are specified within the message itself via ``setTo()``, ``setCc()``
and ``setBcc()``. Swift Mailer reads these recipients from the message when it
gets sent so that it knows where to send the message to.
Message recipients are one of three types:
* ``To:`` recipients -- the primary recipients (required)
* ``Cc:`` recipients -- receive a copy of the message (optional)
* ``Bcc:`` recipients -- hidden from other recipients (optional)
Each type can contain one, or several addresses. It's possible to list only
the addresses of the recipients, or you can personalize the address by
providing the real name of the recipient.
.. sidebar:: Syntax for Addresses
If you only wish to refer to a single email address (for example your
``From:`` address) then you can just use a string.
.. code-block:: php
$message->setFrom('some@address.tld');
If you want to include a name then you must use an associative array.
.. code-block:: php
$message->setFrom(array('some@address.tld' => 'The Name'));
If you want to include multiple addresses then you must use an array.
.. code-block:: php
$message->setTo(array('some@address.tld', 'other@address.tld'));
You can mix personalized (addresses with a name) and non-personalized
addresses in the same list by mixing the use of associative and
non-associative array syntax.
.. code-block:: php
$message->setTo(array(
'recipient-with-name@example.org' => 'Recipient Name One',
'no-name@example.org', // Note that this is not a key-value pair
'named-recipient@example.org' => 'Recipient Name Two'
));
Setting ``To:`` Recipients
~~~~~~~~~~~~~~~~~~~~~~~~~~
``To:`` recipients are required in a message and are set with the
``setTo()`` or ``addTo()`` methods of the message.
To set ``To:`` recipients, create the message object using either
``new Swift_Message( ... )`` or ``Swift_Message::newInstance( ... )``,
then call the ``setTo()`` method with a complete array of addresses, or use the
``addTo()`` method to iteratively add recipients.
The ``setTo()`` method accepts input in various formats as described earlier in
this chapter. The ``addTo()`` method takes either one or two parameters. The
first being the email address and the second optional parameter being the name
of the recipient.
``To:`` recipients are visible in the message headers and will be
seen by the other recipients.
.. note::
Multiple calls to ``setTo()`` will not add new recipients -- each
call overrides the previous calls. If you want to iteratively add
recipients, use the ``addTo()`` method.
.. code-block:: php
// Using setTo() to set all recipients in one go
$message->setTo(array(
'person1@example.org',
'person2@otherdomain.org' => 'Person 2 Name',
'person3@example.org',
'person4@example.org',
'person5@example.org' => 'Person 5 Name'
));
// Using addTo() to add recipients iteratively
$message->addTo('person1@example.org');
$message->addTo('person2@example.org', 'Person 2 Name');
Setting ``Cc:`` Recipients
~~~~~~~~~~~~~~~~~~~~~~~~~~
``Cc:`` recipients are set with the ``setCc()`` or ``addCc()`` methods of the
message.
To set ``Cc:`` recipients, create the message object using either
``new Swift_Message( ... )`` or ``Swift_Message::newInstance( ... )``, then call
the ``setCc()`` method with a complete array of addresses, or use the
``addCc()`` method to iteratively add recipients.
The ``setCc()`` method accepts input in various formats as described earlier in
this chapter. The ``addCc()`` method takes either one or two parameters. The
first being the email address and the second optional parameter being the name
of the recipient.
``Cc:`` recipients are visible in the message headers and will be
seen by the other recipients.
.. note::
Multiple calls to ``setCc()`` will not add new recipients -- each
call overrides the previous calls. If you want to iteratively add Cc:
recipients, use the ``addCc()`` method.
.. code-block:: php
// Using setCc() to set all recipients in one go
$message->setCc(array(
'person1@example.org',
'person2@otherdomain.org' => 'Person 2 Name',
'person3@example.org',
'person4@example.org',
'person5@example.org' => 'Person 5 Name'
));
// Using addCc() to add recipients iteratively
$message->addCc('person1@example.org');
$message->addCc('person2@example.org', 'Person 2 Name');
Setting ``Bcc:`` Recipients
~~~~~~~~~~~~~~~~~~~~~~~~~~~
``Bcc:`` recipients receive a copy of the message without anybody else knowing
it, and are set with the ``setBcc()`` or ``addBcc()`` methods of the message.
To set ``Bcc:`` recipients, create the message object using either ``new
Swift_Message( ... )`` or ``Swift_Message::newInstance( ... )``, then call the
``setBcc()`` method with a complete array of addresses, or use
the ``addBcc()`` method to iteratively add recipients.
The ``setBcc()`` method accepts input in various formats as described earlier in
this chapter. The ``addBcc()`` method takes either one or two parameters. The
first being the email address and the second optional parameter being the name
of the recipient.
Only the individual ``Bcc:`` recipient will see their address in the message
headers. Other recipients (including other ``Bcc:`` recipients) will not see the
address.
.. note::
Multiple calls to ``setBcc()`` will not add new recipients -- each
call overrides the previous calls. If you want to iteratively add Bcc:
recipients, use the ``addBcc()`` method.
.. code-block:: php
// Using setBcc() to set all recipients in one go
$message->setBcc(array(
'person1@example.org',
'person2@otherdomain.org' => 'Person 2 Name',
'person3@example.org',
'person4@example.org',
'person5@example.org' => 'Person 5 Name'
));
// Using addBcc() to add recipients iteratively
$message->addBcc('person1@example.org');
$message->addBcc('person2@example.org', 'Person 2 Name');
Specifying Sender Details
-------------------------
An email must include information about who sent it. Usually this is managed
by the ``From:`` address, however there are other options.
The sender information is contained in three possible places:
* ``From:`` -- the address(es) of who wrote the message (required)
* ``Sender:`` -- the address of the single person who sent the message
(optional)
* ``Return-Path:`` -- the address where bounces should go to (optional)
You must always include a ``From:`` address by using ``setFrom()`` on the
message. Swift Mailer will use this as the default ``Return-Path:`` unless
otherwise specified.
The ``Sender:`` address exists because the person who actually sent the email
may not be the person who wrote the email. It has a higher precedence than the
``From:`` address and will be used as the ``Return-Path:`` unless otherwise
specified.
Setting the ``From:`` Address
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A ``From:`` address is required and is set with the ``setFrom()`` method of the
message. ``From:`` addresses specify who actually wrote the email, and usually who sent it.
What most people probably don't realise is that you can have more than one
``From:`` address if more than one person wrote the email -- for example if an
email was put together by a committee.
To set the ``From:`` address(es):
* Call the ``setFrom()`` method on the Message.
The ``From:`` address(es) are visible in the message headers and
will be seen by the recipients.
.. note::
If you set multiple ``From:`` addresses then you absolutely must set a
``Sender:`` address to indicate who physically sent the message.
.. code-block:: php
// Set a single From: address
$message->setFrom('your@address.tld');
// Set a From: address including a name
$message->setFrom(array('your@address.tld' => 'Your Name'));
// Set multiple From: addresses if multiple people wrote the email
$message->setFrom(array(
'person1@example.org' => 'Sender One',
'person2@example.org' => 'Sender Two'
));
Setting the ``Sender:`` Address
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A ``Sender:`` address specifies who sent the message and is set with the
``setSender()`` method of the message.
To set the ``Sender:`` address:
* Call the ``setSender()`` method on the Message.
The ``Sender:`` address is visible in the message headers and will be seen by
the recipients.
This address will be used as the ``Return-Path:`` unless otherwise specified.
.. note::
If you set multiple ``From:`` addresses then you absolutely must set a
``Sender:`` address to indicate who physically sent the message.
You must not set more than one sender address on a message because it's not
possible for more than one person to send a single message.
.. code-block:: php
$message->setSender('your@address.tld');
Setting the ``Return-Path:`` (Bounce) Address
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``Return-Path:`` address specifies where bounce notifications should
be sent and is set with the ``setReturnPath()`` method of the message.
You can only have one ``Return-Path:`` and it must not include
a personal name.
To set the ``Return-Path:`` address:
* Call the ``setReturnPath()`` method on the Message.
Bouce notifications will be sent to this address.
.. code-block:: php
$message->setReturnPath('bounces@address.tld');
Requesting a Read Receipt
-------------------------
It is possible to request a read-receipt to be sent to an address when the
email is opened. To request a read receipt set the address with
``setReadReceiptTo()``.
To request a read receipt:
* Set the address you want the receipt to be sent to with the
``setReadReceiptTo()`` method on the Message.
When the email is opened, if the mail client supports it a notification will be sent to this address.
.. note::
Read receipts won't work for the majority of recipients since many mail
clients auto-disable them. Those clients that will send a read receipt
will make the user aware that one has been requested.
.. code-block:: php
$message->setReadReceiptTo('your@address.tld');
Setting the Character Set
-------------------------
The character set of the message (and it's MIME parts) is set with the
``setCharset()`` method. You can also change the global default of UTF-8 by
working with the ``Swift_Preferences`` class.
Swift Mailer will default to the UTF-8 character set unless otherwise
overridden. UTF-8 will work in most instances since it includes all of the
standard US keyboard characters in addition to most international characters.
It is absolutely vital however that you know what character set your message
(or it's MIME parts) are written in otherwise your message may be received
completely garbled.
There are two places in Swift Mailer where you can change the character set:
* In the ``Swift_Preferences`` class
* On each individual message and/or MIME part
To set the character set of your Message:
* Change the global UTF-8 setting by calling
``Swift_Preferences::setCharset()``; or
* Call the ``setCharset()`` method on the message or the MIME part.
.. code-block:: php
// Approach 1: Change the global setting (suggested)
Swift_Preferences::getInstance()->setCharset('iso-8859-2');
// Approach 2: Call the setCharset() method of the message
$message = Swift_Message::newInstance()
->setCharset('iso-8859-2');
// Apprach 3: Specify the charset when setting the body
$message->setBody('My body', 'text/html', 'iso-8859-2');
// Approach 4: Specify the charset for each part added
$message->addPart('My part', 'text/plain', 'iso-8859-2');
Setting the Line Length
-----------------------
The length of lines in a message can be changed by using the ``setMaxLineLength()`` method on the message. It should be kept to less than
1000 characters.
Swift Mailer defaults to using 78 characters per line in a message. This is
done for historical reasons and so that the message can be easily viewed in
plain-text terminals.
To change the maximum length of lines in your Message:
* Call the ``setMaxLineLength()`` method on the Message.
Lines that are longer than the line length specified will be wrapped between
words.
.. note::
You should never set a maximum length longer than 1000 characters
according to RFC 2822. Doing so could have unspecified side-effects such
as truncating parts of your message when it is transported between SMTP
servers.
.. code-block:: php
$message->setMaxLineLength(1000);
Setting the Message Priority
----------------------------
You can change the priority of the message with ``setPriority()``. Setting the
priority will not change the way your email is sent -- it is purely an
indicative setting for the recipient.
The priority of a message is an indication to the recipient what significance
it has. Swift Mailer allows you to set the priority by calling the ``setPriority`` method. This method takes an integer value between 1 and 5:
* Highest
* High
* Normal
* Low
* Lowest
To set the message priority:
* Set the priority as an integer between 1 and 5 with the ``setPriority()``
method on the Message.
.. code-block:: php
// Indicate "High" priority
$message->setPriority(2);

View File

@@ -0,0 +1,161 @@
Library Overview
================
Most features (and more) of your every day mail client software are provided
by Swift Mailer, using object-oriented PHP code as the interface.
In this chapter we will take a short tour of the various components, which put
together form the Swift Mailer library as a whole. You will learn key
terminology used throughout the rest of this book and you will gain a little
understanding of the classes you will work with as you integrate Swift Mailer
into your application.
This chapter is intended to prepare you for the information contained in the
subsequent chapters of this book. You may choose to skip this chapter if you
are fairly technically minded, though it is likely to save you some time in
the long run if you at least read between the lines here.
System Requirements
-------------------
The basic requirements to operate Swift Mailer are extremely minimal and
easily achieved. Historically, Swift Mailer has supported both PHP 4 and PHP 5
by following a parallel development workflow. Now in it's fourth major
version, and Swift Mailer operates on servers running PHP 5.2 or higher.
The library aims to work with as many PHP 5 projects as possible:
* PHP 5.2 or higher, with the SPL extension (standard)
* Limited network access to connect to remote SMTP servers
* 8 MB or more memory limit (Swift Mailer uses around 2 MB)
Component Breakdown
-------------------
Swift Mailer is made up of many classes. Each of these classes can be grouped
into a general "component" group which describes the task it is designed to
perform.
We'll take a brief look at the components which form Swift Mailer in this
section of the book.
The Mailer
~~~~~~~~~~
The mailer class, ``Swift_Mailer`` is the central class in the library where
all of the other components meet one another. ``Swift_Mailer`` acts as a sort
of message dispatcher, communicating with the underlying Transport to deliver
your Message to all intended recipients.
If you were to dig around in the source code for Swift Mailer you'd notice
that ``Swift_Mailer`` itself is pretty bare. It delegates to other objects for
most tasks and in theory, if you knew the internals of Swift Mailer well you
could by-pass this class entirely. We wouldn't advise doing such a thing
however -- there are reasons this class exists:
* for consistency, regardless of the Transport used
* to provide abstraction from the internals in the event internal API changes
are made
* to provide convenience wrappers around aspects of the internal API
An instance of ``Swift_Mailer`` is created by the developer before sending any
Messages.
Transports
~~~~~~~~~~
Transports are the classes in Swift Mailer that are responsible for
communicating with a service in order to deliver a Message. There are several
types of Transport in Swift Mailer, all of which implement the Swift_Transport
interface and offer underlying start(), stop() and send() methods.
Typically you will not need to know how a Transport works under-the-surface,
you will only need to know how to create an instance of one, and which one to
use for your environment.
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| Class | Features | Pros/cons |
+=================================+=============================================================================================+===============================================================================================================================================+
| ``Swift_SmtpTransport`` | Sends messages over SMTP; Supports Authentication; Supports Encryption | Very portable; Pleasingly predictable results; Provides good feedback |
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| ``Swift_SendmailTransport`` | Communicates with a locally installed ``sendmail`` executable (Linux/UNIX) | Quick time-to-run; Provides less-accurate feedback than SMTP; Requires ``sendmail`` installation |
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| ``Swift_MailTransport`` | Uses PHP's built-in ``mail()`` function | Very portable; Potentially unpredictable results; Provides extremely weak feedback |
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| ``Swift_LoadBalancedTransport`` | Cycles through a collection of the other Transports to manage load-reduction | Provides graceful fallback if one Transport fails (e.g. an SMTP server is down); Keeps the load on remote services down by spreading the work |
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| ``Swift_FailoverTransport`` | Works in conjunction with a collection of the other Transports to provide high-availability | Provides graceful fallback if one Transport fails (e.g. an SMTP server is down) |
+---------------------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
MIME Entities
~~~~~~~~~~~~~
Everything that forms part of a Message is called a MIME Entity. All MIME
entities in Swift Mailer share a common set of features. There are various
types of MIME entity that serve different purposes such as Attachments and
MIME parts.
An e-mail message is made up of several relatively simple entities that are
combined in different ways to achieve different results. All of these entities
have the same fundamental outline but serve a different purpose. The Message
itself can be defined as a MIME entity, an Attachment is a MIME entity, all
MIME parts are MIME entities -- and so on!
The basic units of each MIME entity -- be it the Message itself, or an
Attachment -- are its Headers and its body:
.. code-block:: text
Other-Header: Another value
The body content itself
The Headers of a MIME entity, and its body must conform to some strict
standards defined by various RFC documents. Swift Mailer ensures that these
specifications are followed by using various types of object, including
Encoders and different Header types to generate the entity.
Each MIME component implements the base ``Swift_Mime_MimeEntity`` interface,
which offers methods for retrieving Headers, adding new Headers, changing the
Encoder, updating the body and so on!
All MIME entities have one Header in common -- the Content-Type Header,
updated with the entity's ``setContentType()`` method.
Encoders
~~~~~~~~
Encoders are used to transform the content of Messages generated in Swift
Mailer into a format that is safe to send across the internet and that
conforms to RFC specifications.
Generally speaking you will not need to interact with the Encoders in Swift
Mailer -- the correct settings will be handled by the library itself.
However they are probably worth a brief mention in the event that you do want
to play with them.
Both the Headers and the body of all MIME entities (including the Message
itself) use Encoders to ensure the data they contain can be sent over the
internet without becoming corrupted or misinterpreted.
There are two types of Encoder: Base64 and Quoted-Printable.
Plugins
~~~~~~~
Plugins exist to extend, or modify the behaviour of Swift Mailer. They respond
to Events that are fired within the Transports during sending.
There are a number of Plugins provided as part of the base Swift Mailer
package and they all follow a common interface to respond to Events fired
within the library. Interfaces are provided to "listen" to each type of Event
fired and to act as desired when a listened-to Event occurs.
Although several plugins are provided with Swift Mailer out-of-the-box, the
Events system has been specifically designed to make it easy for experienced
object-oriented developers to write their own plugins in order to achieve
goals that may not be possible with the base library.

View File

@@ -0,0 +1,385 @@
Plugins
=======
Plugins are provided with Swift Mailer and can be used to extend the behavior
of the library in ways that simple class inheritance would be more complex.
AntiFlood Plugin
----------------
Many SMTP servers have limits on the number of messages that may be sent
during any single SMTP connection. The AntiFlood plugin provides a way to stay
within this limit while still managing a large number of emails.
A typical limit for a single connection is 100 emails. If the server you
connect to imposes such a limit, it expects you to disconnect after that
number of emails has been sent. You could manage this manually within a loop,
but the AntiFlood plugin provides the necessary wrapper code so that you don't
need to worry about this logic.
Regardless of limits imposed by the server, it's usually a good idea to be
conservative with the resources of the SMTP server. Sending will become
sluggish if the server is being over-used so using the AntiFlood plugin will
not be a bad idea even if no limits exist.
The AntiFlood plugin's logic is basically to disconnect and the immediately
re-connect with the SMTP server every X number of emails sent, where X is a
number you specify to the plugin.
You can also specify a time period in seconds that Swift Mailer should pause
for between the disconnect/re-connect process. It's a good idea to pause for a
short time (say 30 seconds every 100 emails) simply to give the SMTP server a
chance to process its queue and recover some resources.
Using the AntiFlood Plugin
~~~~~~~~~~~~~~~~~~~~~~~~~~
The AntiFlood Plugin -- like all plugins -- is added with the Mailer class'
``registerPlugin()`` method. It takes two constructor parameters: the number of
emails to pause after, and optionally the number of seconds to pause for.
To use the AntiFlood plugin:
* Create an instance of the Mailer using any Transport you choose.
* Create an instance of the ``Swift_Plugins_AntiFloodPlugin`` class, passing
in one or two constructor parameters.
* Register the plugin using the Mailer's ``registerPlugin()`` method.
* Continue using Swift Mailer to send messages as normal.
When Swift Mailer sends messages it will count the number of messages that
have been sent since the last re-connect. Once the number hits your specified
threshold it will disconnect and re-connect, optionally pausing for a
specified amount of time.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Mailer using any Transport
$mailer = Swift_Mailer::newInstance(
Swift_SmtpTransport::newInstance('smtp.example.org', 25)
);
// Use AntiFlood to re-connect after 100 emails
$mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100));
// And specify a time in seconds to pause for (30 secs)
$mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100, 30));
// Continue sending as normal
for ($lotsOfRecipients as $recipient) {
...
$mailer->send( ... );
}
Throttler Plugin
----------------
If your SMTP server has restrictions in place to limit the rate at which you
send emails, then your code will need to be aware of this rate-limiting. The
Throttler plugin makes Swift Mailer run at a rate-limited speed.
Many shared hosts don't open their SMTP servers as a free-for-all. Usually
they have policies in place (probably to discourage spammers) that only allow
you to send a fixed number of emails per-hour/day.
The Throttler plugin supports two modes of rate-limiting and with each, you
will need to do that math to figure out the values you want. The plugin can
limit based on the number of emails per minute, or the number of
bytes-transferred per-minute.
Using the Throttler Plugin
~~~~~~~~~~~~~~~~~~~~~~~~~~
The Throttler Plugin -- like all plugins -- is added with the Mailer class'
``registerPlugin()`` method. It has two required constructor parameters that
tell it how to do its rate-limiting.
To use the Throttler plugin:
* Create an instance of the Mailer using any Transport you choose.
* Create an instance of the ``Swift_Plugins_ThrottlerPlugin`` class, passing
the number of emails, or bytes you wish to limit by, along with the mode
you're using.
* Register the plugin using the Mailer's ``registerPlugin()`` method.
* Continue using Swift Mailer to send messages as normal.
When Swift Mailer sends messages it will keep track of the rate at which sending
messages is occurring. If it realises that sending is happening too fast, it
will cause your program to ``sleep()`` for enough time to average out the rate.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Mailer using any Transport
$mailer = Swift_Mailer::newInstance(
Swift_SmtpTransport::newInstance('smtp.example.org', 25)
);
// Rate limit to 100 emails per-minute
$mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin(
100, Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE
));
// Rate limit to 10MB per-minute
$mailer->registerPlugin(new Swift_Plugins_ThrottlerPlugin(
1024 * 1024 * 10, Swift_Plugins_ThrottlerPlugin::BYTES_PER_MINUTE
));
// Continue sending as normal
for ($lotsOfRecipients as $recipient) {
...
$mailer->send( ... );
}
Logger Plugin
-------------
The Logger plugins helps with debugging during the process of sending. It can
help to identify why an SMTP server is rejecting addresses, or any other
hard-to-find problems that may arise.
The Logger plugin comes in two parts. There's the plugin itself, along with
one of a number of possible Loggers that you may choose to use. For example,
the logger may output messages directly in realtime, or it may capture
messages in an array.
One other notable feature is the way in which the Logger plugin changes
Exception messages. If Exceptions are being thrown but the error message does
not provide conclusive information as to the source of the problem (such as an
ambiguous SMTP error) the Logger plugin includes the entire SMTP transcript in
the error message so that debugging becomes a simpler task.
There are a few available Loggers included with Swift Mailer, but writing your
own implementation is incredibly simple and is achieved by creating a short
class that implements the ``Swift_Plugins_Logger`` interface.
* ``Swift_Plugins_Loggers_ArrayLogger``: Keeps a collection of log messages
inside an array. The array content can be cleared or dumped out to the
screen.
* ``Swift_Plugins_Loggers_EchoLogger``: Prints output to the screen in
realtime. Handy for very rudimentary debug output.
Using the Logger Plugin
~~~~~~~~~~~~~~~~~~~~~~~
The Logger Plugin -- like all plugins -- is added with the Mailer class'
``registerPlugin()`` method. It accepts an instance of ``Swift_Plugins_Logger``
in its constructor.
To use the Logger plugin:
* Create an instance of the Mailer using any Transport you choose.
* Create an instance of the a Logger implementation of
``Swift_Plugins_Logger``.
* Create an instance of the ``Swift_Plugins_LoggerPlugin`` class, passing the
created Logger instance to its constructor.
* Register the plugin using the Mailer's ``registerPlugin()`` method.
* Continue using Swift Mailer to send messages as normal.
* Dump the contents of the log with the logger's ``dump()`` method.
When Swift Mailer sends messages it will keep a log of all the interactions
with the underlying Transport being used. Depending upon the Logger that has
been used the behaviour will differ, but all implementations offer a way to
get the contents of the log.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Mailer using any Transport
$mailer = Swift_Mailer::newInstance(
Swift_SmtpTransport::newInstance('smtp.example.org', 25)
);
// To use the ArrayLogger
$logger = new Swift_Plugins_Loggers_ArrayLogger();
$mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger));
// Or to use the Echo Logger
$logger = new Swift_Plugins_Loggers_EchoLogger();
$mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($logger));
// Continue sending as normal
for ($lotsOfRecipients as $recipient) {
...
$mailer->send( ... );
}
// Dump the log contents
// NOTE: The EchoLogger dumps in realtime so dump() does nothing for it
echo $logger->dump();
Decorator Plugin
----------------
Often there's a need to send the same message to multiple recipients, but with
tiny variations such as the recipient's name being used inside the message
body. The Decorator plugin aims to provide a solution for allowing these small
differences.
The decorator plugin works by intercepting the sending process of Swift
Mailer, reading the email address in the To: field and then looking up a set
of replacements for a template.
While the use of this plugin is simple, it is probably the most commonly
misunderstood plugin due to the way in which it works. The typical mistake
users make is to try registering the plugin multiple times (once for each
recipient) -- inside a loop for example. This is incorrect.
The Decorator plugin should be registered just once, but containing the list
of all recipients prior to sending. It will use this list of recipients to
find the required replacements during sending.
Using the Decorator Plugin
~~~~~~~~~~~~~~~~~~~~~~~~~~
To use the Decorator plugin, simply create an associative array of replacements
based on email addresses and then use the mailer's ``registerPlugin()`` method
to add the plugin.
First create an associative array of replacements based on the email addresses
you'll be sending the message to.
.. note::
The replacements array becomes a 2-dimensional array whose keys are the
email addresses and whose values are an associative array of replacements
for that email address. The curly braces used in this example can be any
type of syntax you choose, provided they match the placeholders in your
email template.
.. code-block:: php
$replacements = array();
foreach ($users as $user) {
$replacements[$user['email']] = array(
'{username}'=>$user['username'],
'{password}'=>$user['password']
);
}
Now create an instance of the Decorator plugin using this array of replacements
and then register it with the Mailer. Do this only once!
.. code-block:: php
$decorator = new Swift_Plugins_DecoratorPlugin($replacements);
$mailer->registerPlugin($decorator);
When you create your message, replace elements in the body (and/or the subject
line) with your placeholders.
.. code-block:: php
$message = Swift_Message::newInstance()
->setSubject('Important notice for {username}')
->setBody(
"Hello {username}, we have reset your password to {password}\n" .
"Please log in and change it at your earliest convenience."
)
;
foreach ($users as $user) {
$message->addTo($user['email']);
}
When you send this message to each of your recipients listed in your
``$replacements`` array they will receive a message customized for just
themselves. For example, the message used above when received may appear like
this to one user:
.. code-block:: text
Subject: Important notice for smilingsunshine2009
Hello smilingsunshine2009, we have reset your password to rainyDays
Please log in and change it at your earliest convenience.
While another use may receive the message as:
.. code-block:: text
Subject: Important notice for billy-bo-bob
Hello billy-bo-bob, we have reset your password to dancingOctopus
Please log in and change it at your earliest convenience.
While the decorator plugin provides a means to solve this problem, there are
various ways you could tackle this problem without the need for a plugin.
We're trying to come up with a better way ourselves and while we have several
(obvious) ideas we don't quite have the perfect solution to go ahead and
implement it. Watch this space.
Providing Your Own Replacements Lookup for the Decorator
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Filling an array with replacements may not be the best solution for providing
replacement information to the decorator. If you have a more elegant algorithm
that performs replacement lookups on-the-fly you may provide your own
implementation.
Providing your own replacements lookup implementation for the Decorator is
simply a matter of passing an instance of ``Swift_Plugins_Decorator_Replacements`` to the decorator plugin's constructor,
rather than passing in an array.
The Replacements interface is very simple to implement since it has just one
method: ``getReplacementsFor($address)``.
Imagine you want to look up replacements from a database on-the-fly, you might
provide an implementation that does this. You need to create a small class.
.. code-block:: php
class DbReplacements implements Swift_Plugins_Decorator_Replacements {
public function getReplacementsFor($address) {
$sql = sprintf(
"SELECT * FROM user WHERE email = '%s'",
mysql_real_escape_string($address)
);
$result = mysql_query($sql);
if ($row = mysql_fetch_assoc($result)) {
return array(
'{username}'=>$row['username'],
'{password}'=>$row['password']
);
}
}
}
Now all you need to do is pass an instance of your class into the Decorator
plugin's constructor instead of passing an array.
.. code-block:: php
$decorator = new Swift_Plugins_DecoratorPlugin(new DbReplacements());
$mailer->registerPlugin($decorator);
For each message sent, the plugin will call your class' ``getReplacementsFor()``
method to find the array of replacements it needs.
.. note::
If your lookup algorithm is case sensitive, you should transform the
``$address`` argument as appropriate -- for example by passing it
through ``strtolower()``.

View File

@@ -0,0 +1,592 @@
Sending Messages
================
Quick Reference for Sending a Message
-------------------------------------
Sending a message is very straightforward. You create a Transport, use it to
create the Mailer, then you use the Mailer to send the message.
To send a Message:
* Create a Transport from one of the provided Transports --
``Swift_SmtpTransport``, ``Swift_SendmailTransport``, ``Swift_MailTransport``
or one of the aggregate Transports.
* Create an instance of the ``Swift_Mailer`` class, using the Transport as
it's constructor parameter.
* Create a Message.
* Send the message via the ``send()`` method on the Mailer object.
.. caution::
The ``Swift_SmtpTransport`` and ``Swift_SendmailTransport`` transports use
``proc_*`` PHP functions, which might not be available on your PHP
installation. You can easily check if that the case by running the
following PHP script: ``<?php echo function_exists('proc_open') ? "Yep,
that will work" : "Sorry, that won't work"; ``
When using ``send()`` the message will be sent just like it would be sent if you
used your mail client. An integer is returned which includes the number of
successful recipients. If none of the recipients could be sent to then zero will
be returned, which equates to a boolean ``false``. If you set two ``To:``
recipients and three ``Bcc:`` recipients in the message and all of the
recipients are delivered to successfully then the value 5 will be returned.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25)
->setUsername('your username')
->setPassword('your password')
;
/*
You could alternatively use a different transport such as Sendmail or Mail:
// Sendmail
$transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');
// Mail
$transport = Swift_MailTransport::newInstance();
*/
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
// Create a message
$message = Swift_Message::newInstance('Wonderful Subject')
->setFrom(array('john@doe.com' => 'John Doe'))
->setTo(array('receiver@domain.org', 'other@domain.org' => 'A name'))
->setBody('Here is the message itself')
;
// Send the message
$result = $mailer->send($message);
Transport Types
~~~~~~~~~~~~~~~
A Transport is the component which actually does the sending. You need to
provide a Transport object to the Mailer class and there are several possible
options.
Typically you will not need to know how a Transport works under-the-surface,
you will only need to know how to create an instance of one, and which one to
use for your environment.
The SMTP Transport
..................
The SMTP Transport sends messages over the (standardized) Simple Message
Transfer Protocol. It can deal with encryption and authentication.
The SMTP Transport, ``Swift_SmtpTransport`` is without doubt the most commonly
used Transport because it will work on 99% of web servers (I just made that
number up, but you get the idea). All the server needs is the ability to
connect to a remote (or even local) SMTP server on the correct port number
(usually 25).
SMTP servers often require users to authenticate with a username and password
before any mail can be sent to other domains. This is easily achieved using
Swift Mailer with the SMTP Transport.
SMTP is a protocol -- in other words it's a "way" of communicating a job
to be done (i.e. sending a message). The SMTP protocol is the fundamental
basis on which messages are delivered all over the internet 7 days a week, 365
days a year. For this reason it's the most "direct" method of sending messages
you can use and it's the one that will give you the most power and feedback
(such as delivery failures) when using Swift Mailer.
Because SMTP is generally run as a remote service (i.e. you connect to it over
the network/internet) it's extremely portable from server-to-server. You can
easily store the SMTP server address and port number in a configuration file
within your application and adjust the settings accordingly if the code is
moved or if the SMTP server is changed.
Some SMTP servers -- Google for example -- use encryption for security reasons.
Swift Mailer supports using both SSL and TLS encryption settings.
Using the SMTP Transport
^^^^^^^^^^^^^^^^^^^^^^^^
The SMTP Transport is easy to use. Most configuration options can be set with
the constructor.
To use the SMTP Transport you need to know which SMTP server your code needs
to connect to. Ask your web host if you're not sure. Lots of people ask me who
to connect to -- I really can't answer that since it's a setting that's
extremely specific to your hosting environment.
To use the SMTP Transport:
* Call ``Swift_SmtpTransport::newInstance()`` with the SMTP server name and
optionally with a port number (defaults to 25).
* Use the returned object to create the Mailer.
A connection to the SMTP server will be established upon the first call to
``send()``.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25);
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
/*
It's also possible to use multiple method calls
$transport = Swift_SmtpTransport::newInstance()
->setHost('smtp.example.org')
->setPort(25)
;
*/
Encrypted SMTP
^^^^^^^^^^^^^^
You can use SSL or TLS encryption with the SMTP Transport by specifying it as
a parameter or with a method call.
To use encryption with the SMTP Transport:
* Pass the encryption setting as a third parameter to
``Swift_SmtpTransport::newInstance()``; or
* Call the ``setEncryption()`` method on the Transport.
A connection to the SMTP server will be established upon the first call to
``send()``. The connection will be initiated with the correct encryption
settings.
.. note::
For SSL or TLS encryption to work your PHP installation must have
appropriate OpenSSL transports wrappers. You can check if "tls" and/or
"ssl" are present in your PHP installation by using the PHP function
``stream_get_transports()``
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('smtp.example.org', 587, 'ssl');
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
/*
It's also possible to use multiple method calls
$transport = Swift_SmtpTransport::newInstance()
->setHost('smtp.example.org')
->setPort(587)
->setEncryption('ssl')
;
*/
SMTP with a Username and Password
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Some servers require authentication. You can provide a username and password
with ``setUsername()`` and ``setPassword()`` methods.
To use a username and password with the SMTP Transport:
* Create the Transport with ``Swift_SmtpTransport::newInstance()``.
* Call the ``setUsername()`` and ``setPassword()`` methods on the Transport.
Your username and password will be used to authenticate upon first connect
when ``send()`` are first used on the Mailer.
If authentication fails, an Exception of type ``Swift_TransportException`` will
be thrown.
.. note::
If you need to know early whether or not authentication has failed and an
Exception is going to be thrown, call the ``start()`` method on the
created Transport.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport the call setUsername() and setPassword()
$transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25)
->setUsername('username')
->setPassword('password')
;
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
The Sendmail Transport
......................
The Sendmail Transport sends messages by communicating with a locally
installed MTA -- such as ``sendmail``.
The Sendmail Transport, ``Swift_SendmailTransport`` does not directly connect to
any remote services. It is designed for Linux servers that have ``sendmail``
installed. The Transport starts a local ``sendmail`` process and sends messages
to it. Usually the ``sendmail`` process will respond quickly as it spools your
messages to disk before sending them.
The Transport is named the Sendmail Transport for historical reasons
(``sendmail`` was the "standard" UNIX tool for sending e-mail for years). It
will send messages using other transfer agents such as Exim or Postfix despite
its name, provided they have the relevant sendmail wrappers so that they can be
started with the correct command-line flags.
It's a common misconception that because the Sendmail Transport returns a
result very quickly it must therefore deliver messages to recipients quickly
-- this is not true. It's not slow by any means, but it's certainly not
faster than SMTP when it comes to getting messages to the intended recipients.
This is because sendmail itself sends the messages over SMTP once they have
been quickly spooled to disk.
The Sendmail Transport has the potential to be just as smart of the SMTP
Transport when it comes to notifying Swift Mailer about which recipients were
rejected, but in reality the majority of locally installed ``sendmail``
instances are not configured well enough to provide any useful feedback. As such
Swift Mailer may report successful deliveries where they did in fact fail before
they even left your server.
You can run the Sendmail Transport in two different modes specified by command
line flags:
* "``-bs``" runs in SMTP mode so theoretically it will act like the SMTP
Transport
* "``-t``" runs in piped mode with no feedback, but theoretically faster,
though not advised
You can think of the Sendmail Transport as a sort of asynchronous SMTP Transport
-- though if you have problems with delivery failures you should try using the
SMTP Transport instead. Swift Mailer isn't doing the work here, it's simply
passing the work to somebody else (i.e. ``sendmail``).
Using the Sendmail Transport
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To use the Sendmail Transport you simply need to call
``Swift_SendmailTransport::newInstance()`` with the command as a parameter.
To use the Sendmail Transport you need to know where ``sendmail`` or another MTA
exists on the server. Swift Mailer uses a default value of
``/usr/sbin/sendmail``, which should work on most systems.
You specify the entire command as a parameter (i.e. including the command line
flags). Swift Mailer supports operational modes of "``-bs``" (default) and
"``-t``".
.. note::
If you run sendmail in "``-t``" mode you will get no feedback as to whether
or not sending has succeeded. Use "``-bs``" unless you have a reason not to.
To use the Sendmail Transport:
* Call ``Swift_SendmailTransport::newInstance()`` with the command, including
the correct command line flags. The default is to use ``/usr/sbin/sendmail
-bs`` if this is not specified.
* Use the returned object to create the Mailer.
A sendmail process will be started upon the first call to ``send()``. If the
process cannot be started successfully an Exception of type
``Swift_TransportException`` will be thrown.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SendmailTransport::newInstance('/usr/sbin/exim -bs');
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
The Mail Transport
..................
The Mail Transport sends messages by delegating to PHP's internal
``mail()`` function.
In my experience -- and others' -- the ``mail()`` function is not particularly
predictable, or helpful.
Quite notably, the ``mail()`` function behaves entirely differently between
Linux and Windows servers. On linux it uses ``sendmail``, but on Windows it uses
SMTP.
In order for the ``mail()`` function to even work at all ``php.ini`` needs to be
configured correctly, specifying the location of sendmail or of an SMTP server.
The problem with ``mail()`` is that it "tries" to simplify things to the point
that it actually makes things more complex due to poor interface design. The
developers of Swift Mailer have gone to a lot of effort to make the Mail
Transport work with a reasonable degree of consistency.
Serious drawbacks when using this Transport are:
* Unpredictable message headers
* Lack of feedback regarding delivery failures
* Lack of support for several plugins that require real-time delivery feedback
It's a last resort, and we say that with a passion!
Using the Mail Transport
^^^^^^^^^^^^^^^^^^^^^^^^
To use the Mail Transport you simply need to call
``Swift_MailTransport::newInstance()``. It's unlikely you'll need to configure
the Transport.
To use the Mail Transport:
* Call ``Swift_MailTransport::newInstance()``.
* Use the returned object to create the Mailer.
Messages will be sent using the ``mail()`` function.
.. note::
The ``mail()`` function can take a ``$additional_parameters`` parameter.
Swift Mailer sets this to "``-f%s``" by default, where the "%s" is
substituted with the address of the sender (via a ``sprintf()``) at send
time. You may override this default by passing an argument to
``newInstance()``.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_MailTransport::newInstance();
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
Available Methods for Sending Messages
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The Mailer class offers two methods for sending Messages -- ``send()``.
Each behaves in a slightly different way.
When a message is sent in Swift Mailer, the Mailer class communicates with
whichever Transport class you have chosen to use.
Each recipient in the message should either be accepted or rejected by the
Transport. For example, if the domain name on the email address is not
reachable the SMTP Transport may reject the address because it cannot process
it. Whichever method you use -- ``send()`` -- Swift Mailer will return
an integer indicating the number of accepted recipients.
.. note::
It's possible to find out which recipients were rejected -- we'll cover that
later in this chapter.
Using the ``send()`` Method
...........................
The ``send()`` method of the ``Swift_Mailer`` class sends a message using
exactly the same logic as your Desktop mail client would use. Just pass it a
Message and get a result.
To send a Message with ``send()``:
* Create a Transport from one of the provided Transports --
``Swift_SmtpTransport``, ``Swift_SendmailTransport``,
``Swift_MailTransport`` or one of the aggregate Transports.
* Create an instance of the ``Swift_Mailer`` class, using the Transport as
it's constructor parameter.
* Create a Message.
* Send the message via the ``send()`` method on the Mailer object.
The message will be sent just like it would be sent if you used your mail
client. An integer is returned which includes the number of successful
recipients. If none of the recipients could be sent to then zero will be
returned, which equates to a boolean ``false``. If you set two
``To:`` recipients and three ``Bcc:`` recipients in the message and all of the
recipients are delivered to successfully then the value 5 will be returned.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('localhost', 25);
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
// Create a message
$message = Swift_Message::newInstance('Wonderful Subject')
->setFrom(array('john@doe.com' => 'John Doe'))
->setTo(array('receiver@domain.org', 'other@domain.org' => 'A name'))
->setBody('Here is the message itself')
;
// Send the message
$numSent = $mailer->send($message);
printf("Sent %d messages\n", $numSent);
/* Note that often that only the boolean equivalent of the
return value is of concern (zero indicates FALSE)
if ($mailer->send($message))
{
echo "Sent\n";
}
else
{
echo "Failed\n";
}
*/
Sending Emails in Batch
.......................
If you want to send a separate message to each recipient so that only their
own address shows up in the ``To:`` field, follow the following recipe:
* Create a Transport from one of the provided Transports --
``Swift_SmtpTransport``, ``Swift_SendmailTransport``,
``Swift_MailTransport`` or one of the aggregate Transports.
* Create an instance of the ``Swift_Mailer`` class, using the Transport as
it's constructor parameter.
* Create a Message.
* Iterate over the recipients and send message via the ``send()`` method on
the Mailer object.
Each recipient of the messages receives a different copy with only their own
email address on the ``To:`` field.
.. note::
In the following example, two emails are sent. One to each of
``receiver@domain.org`` and ``other@domain.org``. These recipients will
not be aware of each other.
.. code-block:: php
require_once 'lib/swift_required.php';
// Create the Transport
$transport = Swift_SmtpTransport::newInstance('localhost', 25);
// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
// Create a message
$message = Swift_Message::newInstance('Wonderful Subject')
->setFrom(array('john@doe.com' => 'John Doe'))
->setBody('Here is the message itself')
;
// Send the message
$failedRecipients = array();
$numSent = 0;
$to = array('receiver@domain.org', 'other@domain.org' => 'A name');
foreach ($to as $address => $name)
{
if (is_int($address)) {
$message->setTo($name);
} else {
$message->setTo(array($address => $name));
}
$numSent += $mailer->send($message, $failedRecipients);
}
printf("Sent %d messages\n", $numSent);
Finding out Rejected Addresses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It's possible to get a list of addresses that were rejected by the Transport
by using a by-reference parameter to ``send()``.
As Swift Mailer attempts to send the message to each address given to it, if a
recipient is rejected it will be added to the array. You can pass an existing
array, otherwise one will be created by-reference.
Collecting the list of recipients that were rejected can be useful in
circumstances where you need to "prune" a mailing list for example when some
addresses cannot be delivered to.
Getting Failures By-reference
.............................
Collecting delivery failures by-reference with the ``send()`` method is as
simple as passing a variable name to the method call.
To get failed recipients by-reference:
* Pass a by-reference variable name to the ``send()`` method of the Mailer
class.
If the Transport rejects any of the recipients, the culprit addresses will be
added to the array provided by-reference.
.. note::
If the variable name does not yet exist, it will be initialized as an
empty array and then failures will be added to that array. If the variable
already exists it will be type-cast to an array and failures will be added
to it.
.. code-block:: php
$mailer = Swift_Mailer::newInstance( ... );
$message = Swift_Message::newInstance( ... )
->setFrom( ... )
->setTo(array(
'receiver@bad-domain.org' => 'Receiver Name',
'other@domain.org' => 'A name',
'other-receiver@bad-domain.org' => 'Other Name'
))
->setBody( ... )
;
// Pass a variable name to the send() method
if (!$mailer->send($message, $failures))
{
echo "Failures:";
print_r($failures);
}
/*
Failures:
Array (
0 => receiver@bad-domain.org,
1 => other-receiver@bad-domain.org
)
*/

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -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.
*/
/**
* General utility class in Swift Mailer, not to be instantiated.
*
* @package Swift
*
* @author Chris Corbyn
*/
abstract class Swift
{
static $initialized = false;
static $initPath;
/** Swift Mailer Version number generated during dist release process */
const VERSION = '@SWIFT_VERSION_NUMBER@';
/**
* 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 = dirname(__FILE__).'/'.str_replace('_', '/', $class).'.php';
if (!file_exists($path))
{
return;
}
if (self::$initPath && !self::$initialized)
{
self::$initialized = true;
require self::$initPath;
}
require $path;
}
/**
* Configure autoloading using Swift Mailer.
*
* This is designed to play nicely with other autoloaders.
*
* @param string $initPath The init script to load when autoloading the first Swift class
*/
public static function registerAutoload($initPath = null)
{
self::$initPath = $initPath;
spl_autoload_register(array('Swift', 'autoload'));
}
}

View File

@@ -0,0 +1,72 @@
<?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}.
* @package Swift
* @subpackage Mime
* @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
);
}
}

View File

@@ -0,0 +1,175 @@
<?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.
* @package Swift
* @subpackage ByteStream
* @author Chris Corbyn
*/
abstract class Swift_ByteStream_AbstractFilterableInputStream
implements Swift_InputByteStream, Swift_Filterable
{
/** Write sequence */
protected $_sequence = 0;
/** StreamFilters */
private $_filters = array();
/** A buffer for writing */
private $_writeBuffer = '';
/** Bound streams */
private $_mirrors = array();
/**
* Commit the given bytes to the storage medium immediately.
* @param string $bytes
* @access protected
*/
abstract protected function _commit($bytes);
/**
* Flush any buffers/content with immediate effect.
* @access protected
*/
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
*/
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->_filter($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();
}
}
// -- Private methods
/** 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 = '';
}
}

View File

@@ -0,0 +1,188 @@
<?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.
* @package Swift
* @subpackage ByteStream
* @author Chris Corbyn
*/
class Swift_ByteStream_ArrayByteStream
implements Swift_InputByteStream, Swift_OutputByteStream
{
/**
* The internal stack of bytes.
* @var string[]
* @access private
*/
private $_array = array();
/**
* The size of the stack
* @var int
* @access private
*/
private $_arraySize = 0;
/**
* The internal pointer offset.
* @var int
* @access private
*/
private $_offset = 0;
/** Bound streams */
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 boolean
*/
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();
}
}
}

View File

@@ -0,0 +1,234 @@
<?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.
* @package Swift
* @subpackage ByteStream
* @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 string $writable if true
*/
public function __construct($path, $writable = false)
{
$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
* @return string
* @throws Swift_IoException
*/
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);
return $bytes;
}
else
{
$this->_resetReadHandle();
return false;
}
}
/**
* Move the internal read pointer to $byteOffset in the stream.
* @param int $byteOffset
* @return boolean
*/
public function setReadPointer($byteOffset)
{
if (isset($this->_reader))
{
$this->_seekReadStreamToPosition($byteOffset);
}
$this->_offset = $byteOffset;
}
// -- Private methods
/** 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))
{
if (!$this->_reader = fopen($this->_path, 'rb'))
{
throw new Swift_IoException(
'Unable to open file for reading [' . $this->_path . ']'
);
}
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;
}
}

View File

@@ -0,0 +1,60 @@
<?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.
* @package Swift
* @subpackage Encoder
* @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 charactermap
*
* @param string $string
* @param int $startOffset
* @param array $currentMap
* @param mixed $ignoredChars
* @return int
*/
public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars);
/**
* Returns mapType
* @return int mapType
*/
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
* @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();
}

View File

@@ -0,0 +1,91 @@
<?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.
* @package Swift
* @subpackage Encoder
* @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
* @access private
*/
private $_width;
/**
* Creates a new GenericFixedWidthReader using $width bytes per character.
* @param int $width
*/
public function __construct($width)
{
$this->_width = $width;
}
/**
* Returns the complete charactermap
*
* @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 = substr($string, - $ignored);
$currentMap = $this->_width;
return ($strlen - $ignored)/$this->_width;
}
/**
* Returns mapType
* @return int mapType
*/
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
* @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;
}
}

View File

@@ -0,0 +1,82 @@
<?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.
* @package Swift
* @subpackage Encoder
* @author Chris Corbyn
*/
class Swift_CharacterReader_UsAsciiReader
implements Swift_CharacterReader
{
/**
* Returns the complete charactermap
*
* @param string $string
* @param int $startOffset
* @param string $ignoredChars
*/
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
* @return int
*/
public function validateByteSequence($bytes, $size)
{
$byte = reset($bytes);
if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F)
{
return 0;
}
else
{
return -1;
}
}
/**
* Returns the number of bytes which should be read to start each character.
* @return int
*/
public function getInitialByteSize()
{
return 1;
}
}

View File

@@ -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.
*/
/**
* Analyzes UTF-8 characters.
* @package Swift
* @subpackage Encoder
* @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 charactermap
*
* @param string $string
* @param int $startOffset
* @param array $currentMap
* @param mixed $ignoredChars
*/
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
* @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;
}
}

View File

@@ -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.
*/
/**
* A factory for creating CharacterReaders.
* @package Swift
* @subpackage Encoder
* @author Chris Corbyn
*/
interface Swift_CharacterReaderFactory
{
/**
* Returns a CharacterReader suitable for the charset applied.
* @param string $charset
* @return Swift_CharacterReader
*/
public function getReaderFor($charset);
}

View File

@@ -0,0 +1,133 @@
<?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.
* @package Swift
* @subpackage Encoder
* @author Chris Corbyn
*/
class Swift_CharacterReaderFactory_SimpleCharacterReaderFactory
implements Swift_CharacterReaderFactory
{
/**
* A map of charset patterns to their implementation classes.
* @var array
* @access private
*/
private static $_map = array();
/**
* Factories which have already been loaded.
* @var Swift_CharacterReaderFactory[]
* @access private
*/
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];
}
}
}
}

View File

@@ -0,0 +1,86 @@
<?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.
*/
require_once dirname(__FILE__) . '/OutputByteStream.php';
require_once dirname(__FILE__) . '/CharacterReaderFactory.php';
/**
* 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.
* @package Swift
* @subpackage CharacterStream
* @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();
}

View File

@@ -0,0 +1,317 @@
<?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.
* @package Swift
* @subpackage CharacterStream
* @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 creatiing 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);
}
}
}

View File

@@ -0,0 +1,298 @@
<?php
/*
CharacterStream implementation using an array in Swift Mailer.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A CharacterStream implementation which stores characters in an internal array.
* @package Swift
* @subpackage CharacterStream
* @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
* @access private
*/
private $_charReader;
/**
* A factory for creatiing CharacterReader instances.
* @var Swift_CharacterReaderFactory
* @access private
*/
private $_charReaderFactory;
/**
* The character set this stream is using.
* @var string
* @access private
*/
private $_charset;
/**
* The datas 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 unknown_type
*/
private $_currentPos = 0;
/**
* The constructor
*
* @param Swift_CharacterReaderFactory $factory
* @param unknown_type $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:
$end = $this->_currentPos + $length;
$end = $end > $this->_charCount
?$this->_charCount
:$end;
$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);
}
}
}

View File

@@ -0,0 +1,59 @@
<?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).
* @package Swift
* @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 The 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;
}
}

View File

@@ -0,0 +1,348 @@
<?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.
* @package Swift
* @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 Swift_DependencyContainer
*/
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.
* @param string $itemName
* @return boolean
* @see register()
*/
public function has($itemName)
{
return array_key_exists($itemName, $this->_store)
&& isset($this->_store[$itemName]['lookupType']);
}
/**
* Lookup the item with the given $itemName.
* @param string $itemName
* @return mixed
* @throws Swift_DependencyException If the dependency is not found
* @see register()
*/
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.
*
* @param string $itemName
* @return Swift_DependencyContainer
* @see asNewInstanceOf(), asSharedInstanceOf(), asValue()
*/
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 Swift_DependencyContainer
*/
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 Swift_DependencyContainer
*/
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()}.
*
* @param string $className
* @return Swift_DependencyContainer
* @see withDependencies(), addConstructorValue(), addConstructorLookup()
*/
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 Swift_DependencyContainer
*/
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.
*
* @param array $lookups
* @return Swift_DependencyContainer
* @see addConstructorValue(), addConstructorLookup()
*/
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.
*
* @param mixed $value
* @return Swift_DependencyContainer
* @see withDependencies(), addConstructorLookup()
*/
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.
*
* @param string $lookup
* @return Swift_DependencyContainer
* @see withDependencies(), addConstructorValue()
*/
public function addConstructorLookup($lookup)
{
$endPoint =& $this->_getEndPoint();
if (!isset($this->_endPoint['args']))
{
$endPoint['args'] = array();
}
$endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup);
return $this;
}
// -- Private methods
/** 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)
);
}
else
{
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;
}
else
{
return $this->lookup($item);
}
}
}

View File

@@ -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.
*/
/**
* DependencyException thrown when a requested dependeny is missing.
* @package Swift
* @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);
}
}

View File

@@ -0,0 +1,70 @@
<?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.
* @package Swift
* @subpackage Mime
* @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)
);
}
}

View File

@@ -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.
*/
/**
* Interface for all Encoder schemes.
* @package Swift
* @subpackage Encoder
* @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);
}

View File

@@ -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.
*/
/**
* Handles Base 64 Encoding in Swift Mailer.
* @package Swift
* @subpackage Encoder
* @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)
{
}
}

View File

@@ -0,0 +1,296 @@
<?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.
* @package Swift
* @subpackage Encoder
* @author Chris Corbyn
*/
class Swift_Encoder_QpEncoder implements Swift_Encoder
{
/**
* The CharacterStream used for reading characters (as opposed to bytes).
* @var Swift_CharacterStream
* @access protected
*/
protected $_charStream;
/**
* A filter used if input should be canonicalized.
* @var Swift_StreamFilter
* @access protected
*/
protected $_filter;
/**
* Pre-computed QP for HUGE optmization.
* @var string[]
* @access protected
*/
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[]
* @access protected
*/
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);
if ($currentLine && $lineLen+$size >= $thisLineLength)
{
$lines[$lNo] = '';
$currentLine =& $lines[$lNo++];
$thisLineLength = $maxLineLength;
$lineLen=0;
}
$lineLen+=$size;
$currentLine .= $enc;
}
return $this->_standardize(implode("=\r\n", $lines));
}
/**
* Updates the charset used.
* @param string $charset
*/
public function charsetChanged($charset)
{
$this->_charStream->setCharacterSet($charset);
}
// -- Protected methods
/**
* Encode the given byte array into a verbatim QP form.
* @param int[] $bytes
* @return string
* @access protected
*/
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[]
* @access protected
*/
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
* @access protected
*/
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;
}
}

View File

@@ -0,0 +1,87 @@
<?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.
* @package Swift
* @subpackage Encoder
* @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
* @access private
*/
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 to encode
* @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);
}
}

View File

@@ -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.
*/
/**
* Provides quick access to each encoding type.
*
* @package Swift
* @subpackage Encoder
* @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 Methods
private static function _lookup($key)
{
return Swift_DependencyContainer::getInstance()->lookup($key);
}
}

View File

@@ -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.
* @package Swift
* @subpackage Events
* @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;
}
}

View File

@@ -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.
*/
/**
* Listens for Transports to send commands to the server.
* @package Swift
* @subpackage Events
* @author Chris Corbyn
*/
interface Swift_Events_CommandListener extends Swift_Events_EventListener
{
/**
* Invoked immediately following a command being sent.
* @param Swift_Events_ResponseEvent $evt
*/
public function commandSent(Swift_Events_CommandEvent $evt);
}

View File

@@ -0,0 +1,39 @@
<?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.
*
* @package Swift
* @subpackage Events
* @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 boolean $cancel, optional
*/
public function cancelBubble($cancel = true);
/**
* Returns true if this Event will not bubble any further up the stack.
* @return boolean
*/
public function bubbleCancelled();
}

View File

@@ -0,0 +1,79 @@
<?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.
* @package Swift
* @subpackage Events
* @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 boolean $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);
}

View File

@@ -0,0 +1,19 @@
<?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.
* @package Swift
* @subpackage Events
* @author Chris Corbyn
*/
interface Swift_Events_EventListener
{
}

View File

@@ -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.
*/
/**
* A base Event which all Event classes inherit from.
*
* @package Swift
* @subpackage Events
* @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 boolean $cancel, optional
*/
public function cancelBubble($cancel = true)
{
$this->_bubbleCancelled = $cancel;
}
/**
* Returns true if this Event will not bubble any further up the stack.
* @return boolean
*/
public function bubbleCancelled()
{
return $this->_bubbleCancelled;
}
}

View File

@@ -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.
*/
/**
* Generated when a response is received on a SMTP connection.
* @package Swift
* @subpackage Events
* @author Chris Corbyn
*/
class Swift_Events_ResponseEvent extends Swift_Events_EventObject
{
/**
* The overall result.
* @var boolean
*/
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 boolean $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 boolean
*/
public function isValid()
{
return $this->_valid;
}
}

View File

@@ -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.
*/
/**
* Listens for responses from a remote SMTP server.
* @package Swift
* @subpackage Events
* @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);
}

View File

@@ -0,0 +1,120 @@
<?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.
* @package Swift
* @subpackage Events
* @author Chris Corbyn
*/
class Swift_Events_SendEvent extends Swift_Events_EventObject
{
/** Sending has yet to occur */
const RESULT_PENDING = 0x0001;
/** 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.
* @return int
*/
public function setResult($result)
{
$this->_result = $result;
}
/**
* Get the result of this Event.
* The return value is a bitmask from
* {@link RESULT_PENDING, RESULT_SUCCESS, RESULT_TENTATIVE, RESULT_FAILED}
* @return int
*/
public function getResult()
{
return $this->_result;
}
}

View File

@@ -0,0 +1,33 @@
<?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.
* @package Swift
* @subpackage Events
* @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);
}

View File

@@ -0,0 +1,167 @@
<?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.
*
* @package Swift
* @subpackage Events
* @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 boolean $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);
}
// -- Private methods
/** 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);
}
}
}

View File

@@ -0,0 +1,30 @@
<?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).
* @package Swift
* @subpackage Events
* @author Chris Corbyn
*/
class Swift_Events_TransportChangeEvent extends Swift_Events_EventObject
{
/**
* Get the Transport.
* @return Swift_Transport
*/
public function getTransport()
{
return $this->getSource();
}
}

View File

@@ -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.
*/
/**
* Listens for changes within the Transport system.
*
* @package Swift
* @subpackage Events
*
* @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);
}

View File

@@ -0,0 +1,48 @@
<?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.
* @package Swift
* @subpackage Events
* @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;
}
}

View File

@@ -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.
*/
/**
* Listens for Exceptions thrown from within the Transport system.
* @package Swift
* @subpackage Events
* @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);
}

View File

@@ -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.
*/
/**
* Contains a list of redundant Transports so when one fails, the next is used.
* @package Swift
* @subpackage Transport
* @author Chris Corbyn
*/
class Swift_FailoverTransport extends Swift_Transport_FailoverTransport
{
/**
* Creates a new FailoverTransport with $transports.
* @param array $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 string $transports
* @return Swift_FailoverTransport
*/
public static function newInstance($transports = array())
{
return new self($transports);
}
}

View File

@@ -0,0 +1,210 @@
<?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.
* @package Swift
* @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('Unable to create Path ['.$this->_path.']');
}
}
}
/**
* Tests if this Spool mechanism has started.
*
* @return boolean
*/
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 integer $limit
*/
public function setRetryLimit($limit)
{
$this->_retryLimit=$limit;
}
/**
* Queues a message.
* @param Swift_Mime_Message $message The message to store
* @return boolean
* @throws Swift_IoException
*/
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 allready exists, we try a longer fileName
*/
$fileName.=$this->getRandomString(1);
}
}
throw new Swift_IoException('Unable to create a file for enqueuing Message');
}
/**
* Execute a recovery if for anyreason 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 emails
*/
public function flushQueue(Swift_Transport $transport, &$failedRecipients = null)
{
if (!$transport->isStarted())
{
$transport->start();
}
$failedRecipients = (array) $failedRecipients;
$count = 0;
$time = time();
foreach (new DirectoryIterator($this->_path) 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
*/
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;
}
}

View File

@@ -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.
*/
/**
* An OutputByteStream which specifically reads from a file.
* @package Swift
* @subpackage ByteStream
* @author Chris Corbyn
*/
interface Swift_FileStream extends Swift_OutputByteStream
{
/**
* Get the complete path to the file.
* @return string
*/
public function getPath();
}

View File

@@ -0,0 +1,33 @@
<?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.
* @package Swift
* @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);
}

View File

@@ -0,0 +1,60 @@
<?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.
* @package Swift
* @subpackage Mime
* @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 Swift_Mime_EmbeddedFile
*/
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 Swift_Mime_EmbeddedFile
*/
public static function fromPath($path)
{
$image = self::newInstance()->setFile(
new Swift_ByteStream_FileByteStream($path)
);
return $image;
}
}

View File

@@ -0,0 +1,72 @@
<?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.
* @package Swift
* @subpackage ByteStream
* @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
* @return int
* @throws Swift_IoException
*/
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();
}

View File

@@ -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.
* @package Swift
* @author Chris Corbyn
*/
class Swift_IoException extends Swift_SwiftException
{
/**
* Create a new IoException with $message.
* @param string $message
*/
public function __construct($message)
{
parent::__construct($message);
}
}

View File

@@ -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 a mechanism for storing data using two keys.
* @package Swift
* @subpackage KeyCache
* @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.
* @param string $nsKey
* @param string $itemKey
* @param string $string
* @param int $mode
* @see MODE_WRITE, MODE_APPEND
*/
public function setString($nsKey, $itemKey, $string, $mode);
/**
* Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
* @param string $nsKey
* @param string $itemKey
* @param Swift_OutputByteStream $os
* @param int $mode
* @see MODE_WRITE, MODE_APPEND
*/
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
* @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 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 boolean
*/
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);
}

View File

@@ -0,0 +1,204 @@
<?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.
* @package Swift
* @subpackage KeyCache
* @author Chris Corbyn
*/
class Swift_KeyCache_ArrayKeyCache implements Swift_KeyCache
{
/**
* Cache contents.
* @var array
* @access private
*/
private $_contents = array();
/**
* An InputStream for cloning.
* @var Swift_KeyCache_KeyCacheInputStream
* @access private
*/
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.
* @param string $nsKey
* @param string $itemKey
* @param string $string
* @param int $mode
* @see MODE_WRITE, MODE_APPEND
*/
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.
* @param string $nsKey
* @param string $itemKey
* @param Swift_OutputByteStream $os
* @param int $mode
* @see MODE_WRITE, MODE_APPEND
*/
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
* @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 boolean
*/
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]);
}
// -- Private methods
/**
* Initialize the namespace of $nsKey if needed.
* @param string $nsKey
* @access private
*/
private function _prepareCache($nsKey)
{
if (!array_key_exists($nsKey, $this->_contents))
{
$this->_contents[$nsKey] = array();
}
}
}

View File

@@ -0,0 +1,333 @@
<?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.
* @package Swift
* @subpackage KeyCache
* @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
* @access private
*/
private $_stream;
/**
* A path to write to.
* @var string
* @access private
*/
private $_path;
/**
* Stored keys.
* @var array
* @access private
*/
private $_keys = array();
/**
* Will be true if magic_quotes_runtime is turned on.
* @var boolean
* @access private
*/
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.
* @param string $nsKey
* @param string $itemKey
* @param string $string
* @param int $mode
* @throws Swift_IoException
* @see MODE_WRITE, MODE_APPEND
*/
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.
* @param string $nsKey
* @param string $itemKey
* @param Swift_OutputByteStream $os
* @param int $mode
* @see MODE_WRITE, MODE_APPEND
* @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
* @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
* @throws Swift_IoException
*/
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 boolean
*/
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]);
}
}
// -- Private methods
/**
* Initialize the namespace of $nsKey if needed.
* @param string $nsKey
* @access private
*/
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
* @access private
*/
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);
}
}
}

View File

@@ -0,0 +1,112 @@
<?php
/*
A dummy KeyCache used to exclude cache layer from problems
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A basic KeyCache backed by an array.
* @package Swift
* @subpackage KeyCache
* @author Xavier De Cock <xdecock@gmail.com>
*/
class Swift_KeyCache_DummyKeyCache implements Swift_KeyCache
{
/**
* Set a string into the cache under $itemKey for the namespace $nsKey.
* @param string $nsKey
* @param string $itemKey
* @param string $string
* @param int $mode
* @see MODE_WRITE, MODE_APPEND
*/
public function setString($nsKey, $itemKey, $string, $mode)
{}
/**
* Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
* @param string $nsKey
* @param string $itemKey
* @param Swift_OutputByteStream $os
* @param int $mode
* @see MODE_WRITE, MODE_APPEND
*/
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
* @return Swift_InputByteStream
*/
public function getInputByteStream($nsKey, $itemKey,
Swift_InputByteStream $writeThrough = null)
{
return false;
}
/**
* Get data back out of the cache as a string.
* @param string $nsKey
* @param string $itemKey
* @return string
*/
public function getString($nsKey, $itemKey)
{
return false;
}
/**
* 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)
{
return false;
}
/**
* Check if the given $itemKey exists in the namespace $nsKey.
* @param string $nsKey
* @param string $itemKey
* @return boolean
*/
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)
{}
}

View File

@@ -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.
* @package Swift
* @subpackage KeyCache
* @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();
}

View File

@@ -0,0 +1,106 @@
<?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.
* @package Swift
* @subpackage KeyCache
* @author Chris Corbyn
*/
class Swift_KeyCache_NullKeyCache implements Swift_KeyCache
{
/**
* Set a string into the cache under $itemKey for the namespace $nsKey.
* @param string $nsKey
* @param string $itemKey
* @param string $string
* @param int $mode
* @see MODE_WRITE, MODE_APPEND
*/
public function setString($nsKey, $itemKey, $string, $mode)
{
}
/**
* Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
* @param string $nsKey
* @param string $itemKey
* @param Swift_OutputByteStream $os
* @param int $mode
* @see MODE_WRITE, MODE_APPEND
*/
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
* @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 boolean
*/
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)
{
}
}

View File

@@ -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.
*/
/**
* Writes data to a KeyCache using a stream.
* @package Swift
* @subpackage KeyCache
* @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;
}
}

View File

@@ -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.
*/
/**
* Redudantly and rotationally uses several Transport implementations when sending.
* @package Swift
* @subpackage Transport
* @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 string $transports
* @return Swift_LoadBalancedTransport
*/
public static function newInstance($transports = array())
{
return new self($transports);
}
}

View File

@@ -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.
*/
/**
* Sends Messages using the mail() function.
* @package Swift
* @subpackage Transport
* @author Chris Corbyn
*/
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 Swift_MailTransport
*/
public static function newInstance($extraParams = '-f%s')
{
return new self($extraParams);
}
}

View File

@@ -0,0 +1,118 @@
<?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.
*
* @package Swift
* @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 Swift_Mailer
*/
public static function newInstance(Swift_Transport $transport)
{
return new self($transport);
}
/**
* Create a new class instance of one if 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, optional
* @return int
*/
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
* @param string $key
*/
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;
}
}

View File

@@ -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.
*/
/**
* Wraps a standard PHP array in an interator.
* @package Swift
* @subpackage Mailer
* @author Chris Corbyn
*/
class Swift_Mailer_ArrayRecipientIterator
implements Swift_Mailer_RecipientIterator
{
/**
* The list of recipients.
* @var array
* @access private
*/
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 boolean
*/
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);
}
}

View File

@@ -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.
*/
/**
* Provides an abstract way of specifying recipients for batch sending.
* @package Swift
* @subpackage Mailer
* @author Chris Corbyn
*/
interface Swift_Mailer_RecipientIterator
{
/**
* Returns true only if there are more recipients to send to.
* @return boolean
*/
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();
}

View File

@@ -0,0 +1,84 @@
<?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.
* @package Swift
* @author Fabien Potencier
*/
class Swift_MemorySpool implements Swift_Spool
{
protected $messages = array();
/**
* Tests if this Transport mechanism has started.
* @return boolean
*/
public function isStarted()
{
return true;
}
/**
* Starts this Transport mechanism.
*/
public function start()
{
}
/**
* Stops this Transport mechanism.
*/
public function stop()
{
}
/**
* Stores a message in the queue.
*
* @param Swift_Mime_Message $message The message to store
*
* @return boolean Whether the operation has succeeded
*/
public function queueMessage(Swift_Mime_Message $message)
{
$this->messages[] = $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;
while ($message = array_pop($this->messages))
{
$count += $transport->send($message, $failedRecipients);
}
return $count;
}
}

View File

@@ -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.
*/
/**
* The Message class for building emails.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Message extends Swift_Mime_SimpleMessage
{
/**
* 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 Swift_Mime_Message
*/
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
*/
public function addPart($body, $contentType = null, $charset = null)
{
return $this->attach(Swift_MimePart::newInstance(
$body, $contentType, $charset
));
}
public function __wakeup()
{
Swift_DependencyContainer::getInstance()->createDependenciesFor('mime.message');
}
}

View File

@@ -0,0 +1,143 @@
<?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.
* @package Swift
* @subpackage Mime
* @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 Swift_Mime_Attachment
*/
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 Swift_Mime_Attachment
*/
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 Swift_Mime_Attachment
*/
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 Swift_Mime_Attachment
*/
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;
}
}

View File

@@ -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.
*/
/**
* Observes changes in an Mime entity's character set.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
interface Swift_Mime_CharsetObserver
{
/**
* Notify this observer that the entity's charset has changed.
* @param string $charset
*/
public function charsetChanged($charset);
}

View File

@@ -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.
*/
/**
* Interface for all Transfer Encoding schemes.
* @package Swift
* @subpackage Mime
* @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();
}

View File

@@ -0,0 +1,77 @@
<?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.
* @package Swift
* @subpackage Mime
* @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 $in
* @param Swift_InputByteStream $out
* @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;
while (false !== $bytes = $os->read(8190))
{
$encoded = base64_encode($bytes);
$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);
}
}
/**
* Get the name of this encoding scheme.
* Returns the string 'base64'.
* @return string
*/
public function getName()
{
return 'base64';
}
}

View File

@@ -0,0 +1,172 @@
<?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.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Mime_ContentEncoder_PlainContentEncoder
implements Swift_Mime_ContentEncoder
{
/**
* The name of this encoding scheme (probably 7bit or 8bit).
* @var string
* @access private
*/
private $_name;
/**
* True if canonical transformations should be done.
* @var boolean
* @access private
*/
private $_canonical;
/**
* Creates a new PlainContentEncoder with $name (probably 7bit or 8bit).
* @param string $name
* @param boolean $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 $in
* @param Swift_InputByteStream $out
* @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)
{
}
// -- Private methods
/**
* A safer (but weaker) wordwrap for unicode.
* @param string $string
* @param int $length
* @param string $le
* @return string
* @access private
*/
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
* @access private
*/
private function _canonicalize($string)
{
return str_replace(
array("\r\n", "\r", "\n"),
array("\n", "\n", "\r\n"),
$string
);
}
}

View File

@@ -0,0 +1,135 @@
<?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.
* @package Swift
* @subpackage Mime
* @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 boolean $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);
if ($currentLine && $lineLen+$size >= $thisLineLength)
{
$is->write($prepend . $this->_standardize($currentLine));
$currentLine = '';
$prepend = "=\r\n";
$thisLineLength = $maxLineLength;
$lineLen=0;
}
$lineLen+=$size;
$currentLine .= $enc;
}
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';
}
}

View File

@@ -0,0 +1,48 @@
<?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.
* @package Swift
* @subpackage Mime
* @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 {@link LEVEL_RELATED}.
* @return int
*/
public function getNestingLevel()
{
return self::LEVEL_RELATED;
}
}

View File

@@ -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.
*/
/**
* Observes changes for a Mime entity's ContentEncoder.
* @package Swift
* @subpackage Mime
* @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);
}

View File

@@ -0,0 +1,178 @@
<?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.
* @package Swift
* @subpackage Mime
* @author Fabien Potencier
* @author Chris Corbyn
*/
class Swift_Mime_Grammar
{
/**
* Special characters used in the syntax which need to be escaped.
* @var string[]
* @access private
*/
private static $_specials = array();
/**
* Tokens defined in RFC 2822 (and some related RFCs).
* @var string[]
* @access private
*/
private static $_grammar = array();
/**
* Initialize some RFC 2822 (and friends) ABNF grammar definitions.
* @access protected
*/
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 execatly as written in the RFC
* @return string
*/
public function getDefinition($name)
{
if (array_key_exists($name, self::$_grammar))
{
return self::$_grammar[$name];
}
else
{
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 additonal 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;
}
}

View File

@@ -0,0 +1,85 @@
<?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.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
interface Swift_Mime_Header
{
/** Text headers */
const TYPE_TEXT = 2;
/** Parameterized 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.
* @return int
* @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
* @see TYPE_DATE, TYPE_ID, TYPE_PATH
*/
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();
}

View File

@@ -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.
*/
/**
* Interface for all Header Encoding schemes.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
interface Swift_Mime_HeaderEncoder extends Swift_Encoder
{
/**
* Get the MIME name of this content encoding scheme.
* @return string
*/
public function getName();
}

View File

@@ -0,0 +1,61 @@
<?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.
*/
require_once dirname(__FILE__) . '/../HeaderEncoder.php';
require_once dirname(__FILE__) . '/../../Encoder/Base64Encoder.php';
/**
* Handles Base64 (B) Header Encoding in Swift Mailer.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Mime_HeaderEncoder_Base64HeaderEncoder
extends Swift_Encoder_Base64Encoder
implements Swift_Mime_HeaderEncoder
{
/**
* Get the name of this encoding scheme.
* Returns the string 'B'.
* @return string
*/
public function getName()
{
return 'B';
}
/**
* Takes an unencoded string and produces a Base64 encoded string from it.
* If the charset is iso-2022-jp, it uses mb_encode_mimeheader instead of
* default encodeString, otherwise pass to the parent method.
* @param string $string to encode
* @param int $firstLineOffset
* @param int $maxLineLength, optional, 0 indicates the default of 76 bytes
* @param string $charset
* @return string
*/
public function encodeString($string, $firstLineOffset = 0,
$maxLineLength = 0, $charset = 'utf-8')
{
if (strtolower($charset) === 'iso-2022-jp')
{
$old = mb_internal_encoding();
mb_internal_encoding('utf-8');
$newstring = mb_encode_mimeheader($string, $charset, $this->getName(), "\r\n");
mb_internal_encoding($old);
return $newstring;
}
return parent::encodeString($string, $firstLineOffset, $maxLineLength);
}
}

View File

@@ -0,0 +1,70 @@
<?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.
*/
require_once dirname(__FILE__) . '/../HeaderEncoder.php';
require_once dirname(__FILE__) . '/../../Encoder/QpEncoder.php';
require_once dirname(__FILE__) . '/../../CharacterStream.php';
/**
* Handles Quoted Printable (Q) Header Encoding in Swift Mailer.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Mime_HeaderEncoder_QpHeaderEncoder extends Swift_Encoder_QpEncoder
implements Swift_Mime_HeaderEncoder
{
/**
* Creates a new QpHeaderEncoder for the given CharacterStream.
* @param Swift_CharacterStream $charStream to use for reading characters
*/
public function __construct(Swift_CharacterStream $charStream)
{
parent::__construct($charStream);
}
protected function initSafeMap()
{
foreach (array_merge(
range(0x61, 0x7A), range(0x41, 0x5A),
range(0x30, 0x39), array(0x20, 0x21, 0x2A, 0x2B, 0x2D, 0x2F)
) as $byte)
{
$this->_safeMap[$byte] = chr($byte);
}
}
/**
* Get the name of this encoding scheme.
* Returns the string 'Q'.
* @return string
*/
public function getName()
{
return 'Q';
}
/**
* Takes an unencoded string and produces a Q encoded string from it.
* @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, $charst = 'utf-8')
{
return str_replace(array(' ', '=20', "=\r\n"), array('_', '_', "\r\n"),
parent::encodeString($string, $firstLineOffset, $maxLineLength)
);
}
}

View File

@@ -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.
*/
/**
* Creates MIME headers.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
interface Swift_Mime_HeaderFactory extends Swift_Mime_CharsetObserver
{
/**
* Create a new Mailbox Header with a list of $addresses.
* @param string $name
* @param array|string $addresses
* @return Swift_Mime_Header
*/
public function createMailboxHeader($name, $addresses = null);
/**
* Create a new Date header using $timestamp (UNIX time).
* @param string $name
* @param int $timestamp
* @return Swift_Mime_Header
*/
public function createDateHeader($name, $timestamp = null);
/**
* Create a new basic text header with $name and $value.
* @param string $name
* @param string $value
* @return Swift_Mime_Header
*/
public function createTextHeader($name, $value = null);
/**
* Create a new ParameterizedHeader with $name, $value and $params.
* @param string $name
* @param string $value
* @param array $params
* @return Swift_Mime_ParameterizedHeader
*/
public function createParameterizedHeader($name, $value = null,
$params = array());
/**
* Create a new ID header for Message-ID or Content-ID.
* @param string $name
* @param string|array $ids
* @return Swift_Mime_Header
*/
public function createIdHeader($name, $ids = null);
/**
* Create a new Path header with an address (path) in it.
* @param string $name
* @param string $path
* @return Swift_Mime_Header
*/
public function createPathHeader($name, $path = null);
}

View File

@@ -0,0 +1,169 @@
<?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 collection of MIME headers.
*
* @package Swift
* @subpackage Mime
*
* @author Chris Corbyn
*/
interface Swift_Mime_HeaderSet extends Swift_Mime_CharsetObserver
{
/**
* Add a new Mailbox Header with a list of $addresses.
*
* @param string $name
* @param array|string $addresses
*/
public function addMailboxHeader($name, $addresses = null);
/**
* Add a new Date header using $timestamp (UNIX time).
*
* @param string $name
* @param int $timestamp
*/
public function addDateHeader($name, $timestamp = null);
/**
* Add a new basic text header with $name and $value.
*
* @param string $name
* @param string $value
*/
public function addTextHeader($name, $value = null);
/**
* Add a new ParameterizedHeader with $name, $value and $params.
*
* @param string $name
* @param string $value
* @param array $params
*/
public function addParameterizedHeader($name, $value = null,
$params = array());
/**
* Add a new ID header for Message-ID or Content-ID.
*
* @param string $name
* @param string|array $ids
*/
public function addIdHeader($name, $ids = null);
/**
* Add a new Path header with an address (path) in it.
*
* @param string $name
* @param string $path
*/
public function addPathHeader($name, $path = null);
/**
* Returns true if at least one header with the given $name exists.
*
* If multiple headers match, the actual one may be specified by $index.
*
* @param string $name
* @param int $index
*
* @return boolean
*/
public function has($name, $index = 0);
/**
* Set a header in the HeaderSet.
*
* The header may be a previously fetched header via {@link get()} or it may
* be one that has been created separately.
*
* If $index is specified, the header will be inserted into the set at this
* offset.
*
* @param Swift_Mime_Header $header
* @param int $index
*/
public function set(Swift_Mime_Header $header, $index = 0);
/**
* Get the header with the given $name.
* If multiple headers match, the actual one may be specified by $index.
* Returns NULL if none present.
*
* @param string $name
* @param int $index
*
* @return Swift_Mime_Header
*/
public function get($name, $index = 0);
/**
* Get all headers with the given $name.
*
* @param string $name
*
* @return array
*/
public function getAll($name = null);
/**
* Remove the header with the given $name if it's set.
*
* If multiple headers match, the actual one may be specified by $index.
*
* @param string $name
* @param int $index
*/
public function remove($name, $index = 0);
/**
* Remove all headers with the given $name.
*
* @param string $name
*/
public function removeAll($name);
/**
* Create a new instance of this HeaderSet.
*
* @return Swift_Mime_HeaderSet
*/
public function newInstance();
/**
* Define a list of Header names as an array in the correct order.
*
* These Headers will be output in the given order where present.
*
* @param array $sequence
*/
public function defineOrdering(array $sequence);
/**
* Set a list of header names which must always be displayed when set.
*
* Usually headers without a field value won't be output unless set here.
*
* @param array $names
*/
public function setAlwaysDisplayed(array $names);
/**
* Returns a string with a representation of all headers.
*
* @return string
*/
public function toString();
}

View File

@@ -0,0 +1,504 @@
<?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 base MIME Header.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
abstract class Swift_Mime_Headers_AbstractHeader implements Swift_Mime_Header
{
/**
* The name of this Header.
* @var string
* @access private
*/
private $_name;
/**
* The Grammar used for this Header.
* @var Swift_Mime_Grammar
* @access private
*/
private $_grammar;
/**
* The Encoder used to encode this Header.
* @var Swift_Encoder
* @access private
*/
private $_encoder;
/**
* The maximum length of a line in the header.
* @var int
* @access private
*/
private $_lineLength = 78;
/**
* The language used in this Header.
* @var string
*/
private $_lang;
/**
* The character set of the text in this Header.
* @var string
* @access private
*/
private $_charset = 'utf-8';
/**
* The value of this Header, cached.
* @var string
* @access private
*/
private $_cachedValue = null;
/**
* Creates a new Header.
* @param Swift_Mime_Grammar $grammar
*/
public function __construct(Swift_Mime_Grammar $grammar)
{
$this->setGrammar($grammar);
}
/**
* Set the character set used in this Header.
* @param string $charset
*/
public function setCharset($charset)
{
$this->clearCachedValueIf($charset != $this->_charset);
$this->_charset = $charset;
if (isset($this->_encoder))
{
$this->_encoder->charsetChanged($charset);
}
}
/**
* Get the character set used in this Header.
* @return string
*/
public function getCharset()
{
return $this->_charset;
}
/**
* Set the language used in this Header.
* For example, for US English, 'en-us'.
* This can be unspecified.
* @param string $lang
*/
public function setLanguage($lang)
{
$this->clearCachedValueIf($this->_lang != $lang);
$this->_lang = $lang;
}
/**
* Get the language used in this Header.
* @return string
*/
public function getLanguage()
{
return $this->_lang;
}
/**
* Set the encoder used for encoding the header.
* @param Swift_Mime_HeaderEncoder $encoder
*/
public function setEncoder(Swift_Mime_HeaderEncoder $encoder)
{
$this->_encoder = $encoder;
$this->setCachedValue(null);
}
/**
* Get the encoder used for encoding this Header.
* @return Swift_Mime_HeaderEncoder
*/
public function getEncoder()
{
return $this->_encoder;
}
/**
* Set the grammar used for the header.
* @param Swift_Mime_Grammar $grammar
*/
public function setGrammar(Swift_Mime_Grammar $grammar)
{
$this->_grammar = $grammar;
$this->setCachedValue(null);
}
/**
* Get the grammar used for this Header.
* @return Swift_Mime_Grammar
*/
public function getGrammar()
{
return $this->_grammar;
}
/**
* Get the name of this header (e.g. charset).
* @return string
*/
public function getFieldName()
{
return $this->_name;
}
/**
* Set the maximum length of lines in the header (excluding EOL).
* @param int $lineLength
*/
public function setMaxLineLength($lineLength)
{
$this->clearCachedValueIf($this->_lineLength != $lineLength);
$this->_lineLength = $lineLength;
}
/**
* Get the maximum permitted length of lines in this Header.
* @return int
*/
public function getMaxLineLength()
{
return $this->_lineLength;
}
/**
* Get this Header rendered as a RFC 2822 compliant string.
* @return string
* @throws Swift_RfcComplianceException
*/
public function toString()
{
return $this->_tokensToString($this->toTokens());
}
/**
* Returns a string representation of this object.
*
* @return string
*
* @see toString()
*/
public function __toString()
{
return $this->toString();
}
// -- Points of extension
/**
* Set the name of this Header field.
* @param string $name
* @access protected
*/
protected function setFieldName($name)
{
$this->_name = $name;
}
/**
* Produces a compliant, formatted RFC 2822 'phrase' based on the string given.
* @param Swift_Mime_Header $header
* @param string $string as displayed
* @param string $charset of the text
* @param Swift_Mime_HeaderEncoder $encoder
* @param boolean $shorten the first line to make remove for header name
* @return string
*/
protected function createPhrase(Swift_Mime_Header $header, $string, $charset,
Swift_Mime_HeaderEncoder $encoder = null, $shorten = false)
{
//Treat token as exactly what was given
$phraseStr = $string;
//If it's not valid
if (!preg_match('/^' . $this->getGrammar()->getDefinition('phrase') . '$/D', $phraseStr))
{
// .. but it is just ascii text, try escaping some characters
// and make it a quoted-string
if (preg_match('/^' . $this->getGrammar()->getDefinition('text') . '*$/D', $phraseStr))
{
$phraseStr = $this->getGrammar()->escapeSpecials(
$phraseStr, array('"'), $this->getGrammar()->getSpecials()
);
$phraseStr = '"' . $phraseStr . '"';
}
else // ... otherwise it needs encoding
{
//Determine space remaining on line if first line
if ($shorten)
{
$usedLength = strlen($header->getFieldName() . ': ');
}
else
{
$usedLength = 0;
}
$phraseStr = $this->encodeWords($header, $string, $usedLength);
}
}
return $phraseStr;
}
/**
* Encode needed word tokens within a string of input.
* @param string $input
* @param string $usedLength, optional
* @return string
*/
protected function encodeWords(Swift_Mime_Header $header, $input,
$usedLength = -1)
{
$value = '';
$tokens = $this->getEncodableWordTokens($input);
foreach ($tokens as $token)
{
//See RFC 2822, Sect 2.2 (really 2.2 ??)
if ($this->tokenNeedsEncoding($token))
{
//Don't encode starting WSP
$firstChar = substr($token, 0, 1);
switch($firstChar)
{
case ' ':
case "\t":
$value .= $firstChar;
$token = substr($token, 1);
}
if (-1 == $usedLength)
{
$usedLength = strlen($header->getFieldName() . ': ') + strlen($value);
}
$value .= $this->getTokenAsEncodedWord($token, $usedLength);
$header->setMaxLineLength(76); //Forefully override
}
else
{
$value .= $token;
}
}
return $value;
}
/**
* Test if a token needs to be encoded or not.
* @param string $token
* @return boolean
*/
protected function tokenNeedsEncoding($token)
{
return preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token);
}
/**
* Splits a string into tokens in blocks of words which can be encoded quickly.
* @param string $string
* @return string[]
*/
protected function getEncodableWordTokens($string)
{
$tokens = array();
$encodedToken = '';
//Split at all whitespace boundaries
foreach (preg_split('~(?=[\t ])~', $string) as $token)
{
if ($this->tokenNeedsEncoding($token))
{
$encodedToken .= $token;
}
else
{
if (strlen($encodedToken) > 0)
{
$tokens[] = $encodedToken;
$encodedToken = '';
}
$tokens[] = $token;
}
}
if (strlen($encodedToken))
{
$tokens[] = $encodedToken;
}
return $tokens;
}
/**
* Get a token as an encoded word for safe insertion into headers.
* @param string $token to encode
* @param int $firstLineOffset, optional
* @return string
*/
protected function getTokenAsEncodedWord($token, $firstLineOffset = 0)
{
//Adjust $firstLineOffset to account for space needed for syntax
$charsetDecl = $this->_charset;
if (isset($this->_lang))
{
$charsetDecl .= '*' . $this->_lang;
}
$encodingWrapperLength = strlen(
'=?' . $charsetDecl . '?' . $this->_encoder->getName() . '??='
);
if ($firstLineOffset >= 75) //Does this logic need to be here?
{
$firstLineOffset = 0;
}
$encodedTextLines = explode("\r\n",
$this->_encoder->encodeString(
$token, $firstLineOffset, 75 - $encodingWrapperLength, $this->_charset
)
);
if (strtolower($this->_charset) !== 'iso-2022-jp') // special encoding for iso-2022-jp using mb_encode_mimeheader
{
foreach ($encodedTextLines as $lineNum => $line)
{
$encodedTextLines[$lineNum] = '=?' . $charsetDecl .
'?' . $this->_encoder->getName() .
'?' . $line . '?=';
}
}
return implode("\r\n ", $encodedTextLines);
}
/**
* Generates tokens from the given string which include CRLF as individual tokens.
* @param string $token
* @return string[]
* @access protected
*/
protected function generateTokenLines($token)
{
return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE);
}
/**
* Set a value into the cache.
* @param string $value
* @access protected
*/
protected function setCachedValue($value)
{
$this->_cachedValue = $value;
}
/**
* Get the value in the cache.
* @return string
* @access protected
*/
protected function getCachedValue()
{
return $this->_cachedValue;
}
/**
* Clear the cached value if $condition is met.
* @param boolean $condition
* @access protected
*/
protected function clearCachedValueIf($condition)
{
if ($condition)
{
$this->setCachedValue(null);
}
}
// -- Private methods
/**
* Generate a list of all tokens in the final header.
* @param string $string The string to tokenize
* @return array An array of tokens as strings
* @access protected
*/
protected function toTokens($string = null)
{
if (is_null($string))
{
$string = $this->getFieldBody();
}
$tokens = array();
//Generate atoms; split at all invisible boundaries followed by WSP
foreach (preg_split('~(?=[ \t])~', $string) as $token)
{
$tokens = array_merge($tokens, $this->generateTokenLines($token));
}
return $tokens;
}
/**
* Takes an array of tokens which appear in the header and turns them into
* an RFC 2822 compliant string, adding FWSP where needed.
* @param string[] $tokens
* @return string
* @access private
*/
private function _tokensToString(array $tokens)
{
$lineCount = 0;
$headerLines = array();
$headerLines[] = $this->_name . ': ';
$currentLine =& $headerLines[$lineCount++];
//Build all tokens back into compliant header
foreach ($tokens as $i => $token)
{
//Line longer than specified maximum or token was just a new line
if (("\r\n" == $token) ||
($i > 0 && strlen($currentLine . $token) > $this->_lineLength)
&& 0 < strlen($currentLine))
{
$headerLines[] = '';
$currentLine =& $headerLines[$lineCount++];
}
//Append token to the line
if ("\r\n" != $token)
{
$currentLine .= $token;
}
}
//Implode with FWS (RFC 2822, 2.2.3)
return implode("\r\n", $headerLines) . "\r\n";
}
}

View File

@@ -0,0 +1,119 @@
<?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 Date MIME Header for Swift Mailer.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Mime_Headers_DateHeader extends Swift_Mime_Headers_AbstractHeader
{
/**
* The UNIX timestamp value of this Header.
* @var int
* @access private
*/
private $_timestamp;
/**
* Creates a new DateHeader with $name and $timestamp.
* Example:
* <code>
* <?php
* $header = new Swift_Mime_Headers_DateHeader('Date', time());
* ?>
* </code>
* @param string $name of Header
* @param Swift_Mime_Grammar $grammar
*/
public function __construct($name, Swift_Mime_Grammar $grammar)
{
$this->setFieldName($name);
parent::__construct($grammar);
}
/**
* Get the type of Header that this instance represents.
* @return int
* @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
* @see TYPE_DATE, TYPE_ID, TYPE_PATH
*/
public function getFieldType()
{
return self::TYPE_DATE;
}
/**
* Set the model for the field body.
* This method takes a UNIX timestamp.
* @param int $model
*/
public function setFieldBodyModel($model)
{
$this->setTimestamp($model);
}
/**
* Get the model for the field body.
* This method returns a UNIX timestamp.
* @return mixed
*/
public function getFieldBodyModel()
{
return $this->getTimestamp();
}
/**
* Get the UNIX timestamp of the Date in this Header.
* @return int
*/
public function getTimestamp()
{
return $this->_timestamp;
}
/**
* Set the UNIX timestamp of the Date in this Header.
* @param int $timestamp
*/
public function setTimestamp($timestamp)
{
if (!is_null($timestamp))
{
$timestamp = (int) $timestamp;
}
$this->clearCachedValueIf($this->_timestamp != $timestamp);
$this->_timestamp = $timestamp;
}
/**
* Get the string value of the body in this Header.
* This is not necessarily RFC 2822 compliant since folding white space will
* not be added at this stage (see {@link toString()} for that).
* @return string
* @see toString()
*/
public function getFieldBody()
{
if (!$this->getCachedValue())
{
if (isset($this->_timestamp))
{
$this->setCachedValue(date('r', $this->_timestamp));
}
}
return $this->getCachedValue();
}
}

View File

@@ -0,0 +1,166 @@
<?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 ID MIME Header for something like Message-ID or Content-ID.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Mime_Headers_IdentificationHeader
extends Swift_Mime_Headers_AbstractHeader
{
/**
* The IDs used in the value of this Header.
* This may hold multiple IDs or just a single ID.
* @var string[]
* @access private
*/
private $_ids = array();
/**
* Creates a new IdentificationHeader with the given $name and $id.
* @param string $name
* @param Swift_Mime_Grammar $grammar
*/
public function __construct($name, Swift_Mime_Grammar $grammar)
{
$this->setFieldName($name);
parent::__construct($grammar);
}
/**
* Get the type of Header that this instance represents.
* @return int
* @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
* @see TYPE_DATE, TYPE_ID, TYPE_PATH
*/
public function getFieldType()
{
return self::TYPE_ID;
}
/**
* Set the model for the field body.
* This method takes a string ID, or an array of IDs
* @param mixed $model
* @throws Swift_RfcComplianceException
*/
public function setFieldBodyModel($model)
{
$this->setId($model);
}
/**
* Get the model for the field body.
* This method returns an array of IDs
* @return array
*/
public function getFieldBodyModel()
{
return $this->getIds();
}
/**
* Set the ID used in the value of this header.
* @param string|array $id
* @throws Swift_RfcComplianceException
*/
public function setId($id)
{
$this->setIds(is_array($id) ? $id : array($id));
}
/**
* Get the ID used in the value of this Header.
* If multiple IDs are set only the first is returned.
* @return string
*/
public function getId()
{
if (count($this->_ids) > 0)
{
return $this->_ids[0];
}
}
/**
* Set a collection of IDs to use in the value of this Header.
* @param string[] $ids
* @throws Swift_RfcComplianceException
*/
public function setIds(array $ids)
{
$actualIds = array();
foreach ($ids as $id)
{
$this->_assertValidId($id);
$actualIds[] = $id;
}
$this->clearCachedValueIf($this->_ids != $actualIds);
$this->_ids = $actualIds;
}
/**
* Get the list of IDs used in this Header.
* @return string[]
*/
public function getIds()
{
return $this->_ids;
}
/**
* Get the string value of the body in this Header.
* This is not necessarily RFC 2822 compliant since folding white space will
* not be added at this stage (see {@link toString()} for that).
* @return string
* @see toString()
* @throws Swift_RfcComplianceException
*/
public function getFieldBody()
{
if (!$this->getCachedValue())
{
$angleAddrs = array();
foreach ($this->_ids as $id)
{
$angleAddrs[] = '<' . $id . '>';
}
$this->setCachedValue(implode(' ', $angleAddrs));
}
return $this->getCachedValue();
}
/**
* Throws an Exception if the id passed does not comply with RFC 2822.
* @param string $id
* @throws Swift_RfcComplianceException
*/
private function _assertValidId($id)
{
if (!preg_match(
'/^' . $this->getGrammar()->getDefinition('id-left') . '@' .
$this->getGrammar()->getDefinition('id-right') . '$/D',
$id
))
{
throw new Swift_RfcComplianceException(
'Invalid ID given <' . $id . '>'
);
}
}
}

View File

@@ -0,0 +1,326 @@
<?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 Mailbox Address MIME Header for something like From or Sender.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Mime_Headers_MailboxHeader extends Swift_Mime_Headers_AbstractHeader
{
/**
* The mailboxes used in this Header.
* @var string[]
* @access private
*/
private $_mailboxes = array();
/**
* Creates a new MailboxHeader with $name.
* @param string $name of Header
* @param Swift_Mime_HeaderEncoder $encoder
* @param Swift_Mime_Grammar $grammar
*/
public function __construct($name, Swift_Mime_HeaderEncoder $encoder, Swift_Mime_Grammar $grammar)
{
$this->setFieldName($name);
$this->setEncoder($encoder);
parent::__construct($grammar);
}
/**
* Get the type of Header that this instance represents.
* @return int
* @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
* @see TYPE_DATE, TYPE_ID, TYPE_PATH
*/
public function getFieldType()
{
return self::TYPE_MAILBOX;
}
/**
* Set the model for the field body.
* This method takes a string, or an array of addresses.
* @param mixed $model
* @throws Swift_RfcComplianceException
*/
public function setFieldBodyModel($model)
{
$this->setNameAddresses($model);
}
/**
* Get the model for the field body.
* This method returns an associative array like {@link getNameAddresses()}
* @return array
* @throws Swift_RfcComplianceException
*/
public function getFieldBodyModel()
{
return $this->getNameAddresses();
}
/**
* Set a list of mailboxes to be shown in this Header.
* The mailboxes can be a simple array of addresses, or an array of
* key=>value pairs where (email => personalName).
* Example:
* <code>
* <?php
* //Sets two mailboxes in the Header, one with a personal name
* $header->setNameAddresses(array(
* 'chris@swiftmailer.org' => 'Chris Corbyn',
* 'mark@swiftmailer.org' //No associated personal name
* ));
* ?>
* </code>
* @param string|string[] $mailboxes
* @throws Swift_RfcComplianceException
* @see __construct()
* @see setAddresses()
* @see setValue()
*/
public function setNameAddresses($mailboxes)
{
$this->_mailboxes = $this->normalizeMailboxes((array) $mailboxes);
$this->setCachedValue(null); //Clear any cached value
}
/**
* Get the full mailbox list of this Header as an array of valid RFC 2822 strings.
* Example:
* <code>
* <?php
* $header = new Swift_Mime_Headers_MailboxHeader('From',
* array('chris@swiftmailer.org' => 'Chris Corbyn',
* 'mark@swiftmailer.org' => 'Mark Corbyn')
* );
* print_r($header->getNameAddressStrings());
* // array (
* // 0 => Chris Corbyn <chris@swiftmailer.org>,
* // 1 => Mark Corbyn <mark@swiftmailer.org>
* // )
* ?>
* </code>
* @return string[]
* @throws Swift_RfcComplianceException
* @see getNameAddresses()
* @see toString()
*/
public function getNameAddressStrings()
{
return $this->_createNameAddressStrings($this->getNameAddresses());
}
/**
* Get all mailboxes in this Header as key=>value pairs.
* The key is the address and the value is the name (or null if none set).
* Example:
* <code>
* <?php
* $header = new Swift_Mime_Headers_MailboxHeader('From',
* array('chris@swiftmailer.org' => 'Chris Corbyn',
* 'mark@swiftmailer.org' => 'Mark Corbyn')
* );
* print_r($header->getNameAddresses());
* // array (
* // chris@swiftmailer.org => Chris Corbyn,
* // mark@swiftmailer.org => Mark Corbyn
* // )
* ?>
* </code>
* @return string[]
* @see getAddresses()
* @see getNameAddressStrings()
*/
public function getNameAddresses()
{
return $this->_mailboxes;
}
/**
* Makes this Header represent a list of plain email addresses with no names.
* Example:
* <code>
* <?php
* //Sets three email addresses as the Header data
* $header->setAddresses(
* array('one@domain.tld', 'two@domain.tld', 'three@domain.tld')
* );
* ?>
* </code>
* @param string[] $addresses
* @throws Swift_RfcComplianceException
* @see setNameAddresses()
* @see setValue()
*/
public function setAddresses($addresses)
{
$this->setNameAddresses(array_values((array) $addresses));
}
/**
* Get all email addresses in this Header.
* @return string[]
* @see getNameAddresses()
*/
public function getAddresses()
{
return array_keys($this->_mailboxes);
}
/**
* Remove one or more addresses from this Header.
* @param string|string[] $addresses
*/
public function removeAddresses($addresses)
{
$this->setCachedValue(null);
foreach ((array) $addresses as $address)
{
unset($this->_mailboxes[$address]);
}
}
/**
* Get the string value of the body in this Header.
* This is not necessarily RFC 2822 compliant since folding white space will
* not be added at this stage (see {@link toString()} for that).
* @return string
* @throws Swift_RfcComplianceException
* @see toString()
*/
public function getFieldBody()
{
//Compute the string value of the header only if needed
if (is_null($this->getCachedValue()))
{
$this->setCachedValue($this->createMailboxListString($this->_mailboxes));
}
return $this->getCachedValue();
}
// -- Points of extension
/**
* Normalizes a user-input list of mailboxes into consistent key=>value pairs.
* @param string[] $mailboxes
* @return string[]
* @access protected
*/
protected function normalizeMailboxes(array $mailboxes)
{
$actualMailboxes = array();
foreach ($mailboxes as $key => $value)
{
if (is_string($key)) //key is email addr
{
$address = $key;
$name = $value;
}
else
{
$address = $value;
$name = null;
}
$this->_assertValidAddress($address);
$actualMailboxes[$address] = $name;
}
return $actualMailboxes;
}
/**
* Produces a compliant, formatted display-name based on the string given.
* @param string $displayName as displayed
* @param boolean $shorten the first line to make remove for header name
* @return string
* @access protected
*/
protected function createDisplayNameString($displayName, $shorten = false)
{
return $this->createPhrase($this, $displayName,
$this->getCharset(), $this->getEncoder(), $shorten
);
}
/**
* Creates a string form of all the mailboxes in the passed array.
* @param string[] $mailboxes
* @return string
* @throws Swift_RfcComplianceException
* @access protected
*/
protected function createMailboxListString(array $mailboxes)
{
return implode(', ', $this->_createNameAddressStrings($mailboxes));
}
/**
* Redefine the encoding requirements for mailboxes. Commas and semicolons are used to separate
* multiple addresses, and should therefore be encoded
* @param string $token
* @return boolean
*/
protected function tokenNeedsEncoding($token)
{
return preg_match('/[,;]/', $token) || parent::tokenNeedsEncoding($token);
}
// -- Private methods
/**
* Return an array of strings conforming the the name-addr spec of RFC 2822.
* @param string[] $mailboxes
* @return string[]
* @access private
*/
private function _createNameAddressStrings(array $mailboxes)
{
$strings = array();
foreach ($mailboxes as $email => $name)
{
$mailboxStr = $email;
if (!is_null($name))
{
$nameStr = $this->createDisplayNameString($name, empty($strings));
$mailboxStr = $nameStr . ' <' . $mailboxStr . '>';
}
$strings[] = $mailboxStr;
}
return $strings;
}
/**
* Throws an Exception if the address passed does not comply with RFC 2822.
* @param string $address
* @throws Swift_RfcComplianceException If invalid.
* @access private
*/
private function _assertValidAddress($address)
{
if (!preg_match('/^' . $this->getGrammar()->getDefinition('addr-spec') . '$/D',
$address))
{
throw new Swift_RfcComplianceException(
'Address in mailbox given [' . $address .
'] does not comply with RFC 2822, 3.6.2.'
);
}
}
}

View File

@@ -0,0 +1,268 @@
<?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 base MIME Header.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Mime_Headers_ParameterizedHeader
extends Swift_Mime_Headers_UnstructuredHeader
implements Swift_Mime_ParameterizedHeader
{
/**
* RFC 2231's definition of a token.
* @var string
*/
const TOKEN_REGEX = '(?:[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+)';
/**
* The Encoder used to encode the parameters.
* @var Swift_Encoder
* @access private
*/
private $_paramEncoder;
/**
* The parameters as an associative array.
* @var string[]
* @access private
*/
private $_params = array();
/**
* Creates a new ParameterizedHeader with $name.
* @param string $name
* @param Swift_Mime_HeaderEncoder $encoder
* @param Swift_Encoder $paramEncoder, optional
* @param Swift_Mime_Grammar $grammar
*/
public function __construct($name, Swift_Mime_HeaderEncoder $encoder,
Swift_Encoder $paramEncoder = null, Swift_Mime_Grammar $grammar)
{
parent::__construct($name, $encoder, $grammar);
$this->_paramEncoder = $paramEncoder;
}
/**
* Get the type of Header that this instance represents.
* @return int
* @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
* @see TYPE_DATE, TYPE_ID, TYPE_PATH
*/
public function getFieldType()
{
return self::TYPE_PARAMETERIZED;
}
/**
* Set the character set used in this Header.
* @param string $charset
*/
public function setCharset($charset)
{
parent::setCharset($charset);
if (isset($this->_paramEncoder))
{
$this->_paramEncoder->charsetChanged($charset);
}
}
/**
* Set the value of $parameter.
* @param string $parameter
* @param string $value
*/
public function setParameter($parameter, $value)
{
$this->setParameters(array_merge($this->getParameters(), array($parameter => $value)));
}
/**
* Get the value of $parameter.
* @return string
*/
public function getParameter($parameter)
{
$params = $this->getParameters();
return array_key_exists($parameter, $params)
? $params[$parameter]
: null;
}
/**
* Set an associative array of parameter names mapped to values.
* @param string[]
*/
public function setParameters(array $parameters)
{
$this->clearCachedValueIf($this->_params != $parameters);
$this->_params = $parameters;
}
/**
* Returns an associative array of parameter names mapped to values.
* @return string[]
*/
public function getParameters()
{
return $this->_params;
}
/**
* Get the value of this header prepared for rendering.
* @return string
*/
public function getFieldBody() //TODO: Check caching here
{
$body = parent::getFieldBody();
foreach ($this->_params as $name => $value)
{
if (!is_null($value))
{
//Add the parameter
$body .= '; ' . $this->_createParameter($name, $value);
}
}
return $body;
}
// -- Protected methods
/**
* Generate a list of all tokens in the final header.
* This doesn't need to be overridden in theory, but it is for implementation
* reasons to prevent potential breakage of attributes.
* @param string $string The string to tokenize
* @return array An array of tokens as strings
* @access protected
*/
protected function toTokens($string = null)
{
$tokens = parent::toTokens(parent::getFieldBody());
//Try creating any parameters
foreach ($this->_params as $name => $value)
{
if (!is_null($value))
{
//Add the semi-colon separator
$tokens[count($tokens)-1] .= ';';
$tokens = array_merge($tokens, $this->generateTokenLines(
' ' . $this->_createParameter($name, $value)
));
}
}
return $tokens;
}
// -- Private methods
/**
* Render a RFC 2047 compliant header parameter from the $name and $value.
* @param string $name
* @param string $value
* @return string
* @access private
*/
private function _createParameter($name, $value)
{
$origValue = $value;
$encoded = false;
//Allow room for parameter name, indices, "=" and DQUOTEs
$maxValueLength = $this->getMaxLineLength() - strlen($name . '=*N"";') - 1;
$firstLineOffset = 0;
//If it's not already a valid parameter value...
if (!preg_match('/^' . self::TOKEN_REGEX . '$/D', $value))
{
//TODO: text, or something else??
//... and it's not ascii
if (!preg_match('/^' . $this->getGrammar()->getDefinition('text') . '*$/D', $value))
{
$encoded = true;
//Allow space for the indices, charset and language
$maxValueLength = $this->getMaxLineLength() - strlen($name . '*N*="";') - 1;
$firstLineOffset = strlen(
$this->getCharset() . "'" . $this->getLanguage() . "'"
);
}
}
//Encode if we need to
if ($encoded || strlen($value) > $maxValueLength)
{
if (isset($this->_paramEncoder))
{
$value = $this->_paramEncoder->encodeString(
$origValue, $firstLineOffset, $maxValueLength, $this->getCharset()
);
}
else //We have to go against RFC 2183/2231 in some areas for interoperability
{
$value = $this->getTokenAsEncodedWord($origValue);
$encoded = false;
}
}
$valueLines = isset($this->_paramEncoder) ? explode("\r\n", $value) : array($value);
//Need to add indices
if (count($valueLines) > 1)
{
$paramLines = array();
foreach ($valueLines as $i => $line)
{
$paramLines[] = $name . '*' . $i .
$this->_getEndOfParameterValue($line, true, $i == 0);
}
return implode(";\r\n ", $paramLines);
}
else
{
return $name . $this->_getEndOfParameterValue(
$valueLines[0], $encoded, true
);
}
}
/**
* Returns the parameter value from the "=" and beyond.
* @param string $value to append
* @param boolean $encoded
* @param boolean $firstLine
* @return string
* @access private
*/
private function _getEndOfParameterValue($value, $encoded = false, $firstLine = false)
{
if (!preg_match('/^' . self::TOKEN_REGEX . '$/D', $value))
{
$value = '"' . $value . '"';
}
$prepend = '=';
if ($encoded)
{
$prepend = '*=';
if ($firstLine)
{
$prepend = '*=' . $this->getCharset() . "'" . $this->getLanguage() .
"'";
}
}
return $prepend . $value;
}
}

View File

@@ -0,0 +1,140 @@
<?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 Path Header in Swift Mailer, such a Return-Path.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Mime_Headers_PathHeader extends Swift_Mime_Headers_AbstractHeader
{
/**
* The address in this Header (if specified).
* @var string
* @access private
*/
private $_address;
/**
* Creates a new PathHeader with the given $name.
* @param string $name
* @param Swift_Mime_Grammar $grammar
*/
public function __construct($name, Swift_Mime_Grammar $grammar)
{
$this->setFieldName($name);
parent::__construct($grammar);
}
/**
* Get the type of Header that this instance represents.
* @return int
* @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
* @see TYPE_DATE, TYPE_ID, TYPE_PATH
*/
public function getFieldType()
{
return self::TYPE_PATH;
}
/**
* Set the model for the field body.
* This method takes a string for an address.
* @param string $model
* @throws Swift_RfcComplianceException
*/
public function setFieldBodyModel($model)
{
$this->setAddress($model);
}
/**
* Get the model for the field body.
* This method returns a string email address.
* @return mixed
*/
public function getFieldBodyModel()
{
return $this->getAddress();
}
/**
* Set the Address which should appear in this Header.
* @param string $address
* @throws Swift_RfcComplianceException
*/
public function setAddress($address)
{
if (is_null($address))
{
$this->_address = null;
}
elseif ('' == $address)
{
$this->_address = '';
}
else
{
$this->_assertValidAddress($address);
$this->_address = $address;
}
$this->setCachedValue(null);
}
/**
* Get the address which is used in this Header (if any).
* Null is returned if no address is set.
* @return string
*/
public function getAddress()
{
return $this->_address;
}
/**
* Get the string value of the body in this Header.
* This is not necessarily RFC 2822 compliant since folding white space will
* not be added at this stage (see {@link toString()} for that).
* @return string
* @see toString()
*/
public function getFieldBody()
{
if (!$this->getCachedValue())
{
if (isset($this->_address))
{
$this->setCachedValue('<' . $this->_address . '>');
}
}
return $this->getCachedValue();
}
/**
* Throws an Exception if the address passed does not comply with RFC 2822.
* @param string $address
* @throws Swift_RfcComplianceException If invalid.
* @access private
*/
private function _assertValidAddress($address)
{
if (!preg_match('/^' . $this->getGrammar()->getDefinition('addr-spec') . '$/D',
$address))
{
throw new Swift_RfcComplianceException(
'Address set in PathHeader does not comply with addr-spec of RFC 2822.'
);
}
}
}

View File

@@ -0,0 +1,107 @@
<?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 Simple MIME Header.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Mime_Headers_UnstructuredHeader
extends Swift_Mime_Headers_AbstractHeader
{
/**
* The value of this Header.
* @var string
* @access private
*/
private $_value;
/**
* Creates a new SimpleHeader with $name.
* @param string $name
* @param Swift_Mime_HeaderEncoder $encoder
* @param Swift_Mime_Grammar $grammar
*/
public function __construct($name, Swift_Mime_HeaderEncoder $encoder, Swift_Mime_Grammar $grammar)
{
$this->setFieldName($name);
$this->setEncoder($encoder);
parent::__construct($grammar);
}
/**
* Get the type of Header that this instance represents.
* @return int
* @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
* @see TYPE_DATE, TYPE_ID, TYPE_PATH
*/
public function getFieldType()
{
return self::TYPE_TEXT;
}
/**
* Set the model for the field body.
* This method takes a string for the field value.
* @param string $model
*/
public function setFieldBodyModel($model)
{
$this->setValue($model);
}
/**
* Get the model for the field body.
* This method returns a string.
* @return string
*/
public function getFieldBodyModel()
{
return $this->getValue();
}
/**
* Get the (unencoded) value of this header.
* @return string
*/
public function getValue()
{
return $this->_value;
}
/**
* Set the (unencoded) value of this header.
* @param string $value
*/
public function setValue($value)
{
$this->clearCachedValueIf($this->_value != $value);
$this->_value = $value;
}
/**
* Get the value of this header prepared for rendering.
* @return string
*/
public function getFieldBody()
{
if (!$this->getCachedValue())
{
$this->setCachedValue(
$this->encodeWords($this, $this->_value)
);
}
return $this->getCachedValue();
}
}

View File

@@ -0,0 +1,229 @@
<?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 Message (RFC 2822) object.
*
* @package Swift
* @subpackage Mime
*
* @author Chris Corbyn
*/
interface Swift_Mime_Message extends Swift_Mime_MimeEntity
{
/**
* Generates a valid Message-ID and switches to it.
*
* @return string
*/
public function generateId();
/**
* Set the subject of the message.
*
* @param string $subject
*/
public function setSubject($subject);
/**
* Get the subject of the message.
*
* @return string
*/
public function getSubject();
/**
* Set the origination date of the message as a UNIX timestamp.
*
* @param int $date
*/
public function setDate($date);
/**
* Get the origination date of the message as a UNIX timestamp.
*
* @return int
*/
public function getDate();
/**
* Set the return-path (bounce-detect) address.
*
* @param string $address
*/
public function setReturnPath($address);
/**
* Get the return-path (bounce-detect) address.
*
* @return string
*/
public function getReturnPath();
/**
* Set the sender of this message.
*
* If multiple addresses are present in the From field, this SHOULD be set.
*
* According to RFC 2822 it is a requirement when there are multiple From
* addresses, but Swift itself does not require it directly.
*
* An associative array (with one element!) can be used to provide a display-
* name: i.e. array('email@address' => 'Real Name').
*
* If the second parameter is provided and the first is a string, then $name
* is associated with the address.
*
* @param mixed $address
* @param string $name optional
*/
public function setSender($address, $name = null);
/**
* Get the sender address for this message.
*
* This has a higher significance than the From address.
*
* @return string
*/
public function getSender();
/**
* Set the From address of this message.
*
* It is permissible for multiple From addresses to be set using an array.
*
* If multiple From addresses are used, you SHOULD set the Sender address and
* according to RFC 2822, MUST set the sender address.
*
* An array can be used if display names are to be provided: i.e.
* array('email@address.com' => 'Real Name').
*
* If the second parameter is provided and the first is a string, then $name
* is associated with the address.
*
* @param mixed $addresses
* @param string $name optional
*/
public function setFrom($addresses, $name = null);
/**
* Get the From address(es) of this message.
*
* This method always returns an associative array where the keys are the
* addresses.
*
* @return string[]
*/
public function getFrom();
/**
* Set the Reply-To address(es).
*
* Any replies from the receiver will be sent to this address.
*
* It is permissible for multiple reply-to addresses to be set using an array.
*
* This method has the same synopsis as {@link setFrom()} and {@link setTo()}.
*
* If the second parameter is provided and the first is a string, then $name
* is associated with the address.
*
* @param mixed $addresses
* @param string $name optional
*/
public function setReplyTo($addresses, $name = null);
/**
* Get the Reply-To addresses for this message.
*
* This method always returns an associative array where the keys provide the
* email addresses.
*
* @return string[]
*/
public function getReplyTo();
/**
* Set the To address(es).
*
* Recipients set in this field will receive a copy of this message.
*
* This method has the same synopsis as {@link setFrom()} and {@link setCc()}.
*
* If the second parameter is provided and the first is a string, then $name
* is associated with the address.
*
* @param mixed $addresses
* @param string $name optional
*/
public function setTo($addresses, $name = null);
/**
* Get the To addresses for this message.
*
* This method always returns an associative array, whereby the keys provide
* the actual email addresses.
*
* @return string[]
*/
public function getTo();
/**
* Set the Cc address(es).
*
* Recipients set in this field will receive a 'carbon-copy' of this message.
*
* This method has the same synopsis as {@link setFrom()} and {@link setTo()}.
*
* @param mixed $addresses
* @param string $name optional
*/
public function setCc($addresses, $name = null);
/**
* Get the Cc addresses for this message.
*
* This method always returns an associative array, whereby the keys provide
* the actual email addresses.
*
* @return string[]
*/
public function getCc();
/**
* Set the Bcc address(es).
*
* Recipients set in this field will receive a 'blind-carbon-copy' of this
* message.
*
* In other words, they will get the message, but any other recipients of the
* message will have no such knowledge of their receipt of it.
*
* This method has the same synopsis as {@link setFrom()} and {@link setTo()}.
*
* @param mixed $addresses
* @param string $name optional
*/
public function setBcc($addresses, $name = null);
/**
* Get the Bcc addresses for this message.
*
* This method always returns an associative array, whereby the keys provide
* the actual email addresses.
*
* @return string[]
*/
public function getBcc();
}

View File

@@ -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.
*/
/**
* A MIME entity, such as an attachment.
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
interface Swift_Mime_MimeEntity
extends Swift_Mime_CharsetObserver, Swift_Mime_EncodingObserver
{
/** Main message document; there can only be one of these */
const LEVEL_TOP = 16;
/** An entity which nests with the same precedence as an attachment */
const LEVEL_MIXED = 256;
/** An entity which nests with the same precedence as a mime part */
const LEVEL_ALTERNATIVE = 4096;
/** An entity which nests with the same precedence as embedded content */
const LEVEL_RELATED = 65536;
/**
* Get the level at which this entity shall be nested in final document.
* The lower the value, the more outermost the entity will be nested.
* @return int
* @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE
*/
public function getNestingLevel();
/**
* Get the qualified content-type of this mime entity.
* @return string
*/
public function getContentType();
/**
* Returns a unique ID for this entity.
* For most entities this will likely be the Content-ID, though it has
* no explicit semantic meaning and can be considered an identifier for
* programming logic purposes.
* If a Content-ID header is present, this value SHOULD match the value of
* the header.
* @return string
*/
public function getId();
/**
* Get all children nested inside this entity.
* These are not just the immediate children, but all children.
* @return Swift_Mime_MimeEntity[]
*/
public function getChildren();
/**
* Set all children nested inside this entity.
* This includes grandchildren.
* @param Swift_Mime_MimeEntity[] $children
*/
public function setChildren(array $children);
/**
* Get the collection of Headers in this Mime entity.
* @return Swift_Mime_Header[]
*/
public function getHeaders();
/**
* Get the body content of this entity as a string.
* Returns NULL if no body has been set.
* @return string
*/
public function getBody();
/**
* Set the body content of this entity as a string.
* @param string $body
* @param string $contentType optional
*/
public function setBody($body, $contentType = null);
/**
* Get this entire entity in its string form.
* @return string
*/
public function toString();
/**
* Get this entire entity as a ByteStream.
* @param Swift_InputByteStream $is to write to
*/
public function toByteStream(Swift_InputByteStream $is);
}

View File

@@ -0,0 +1,224 @@
<?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 part, in a multipart message.
*
* @package Swift
* @subpackage Mime
* @author Chris Corbyn
*/
class Swift_Mime_MimePart extends Swift_Mime_SimpleMimeEntity
{
/** The format parameter last specified by the user */
protected $_userFormat;
/** The charset last specified by the user */
protected $_userCharset;
/** The delsp parameter last specified by the user */
protected $_userDelSp;
/** The nesting level of this MimePart */
private $_nestingLevel = self::LEVEL_ALTERNATIVE;
/**
* Create a new MimePart 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 string $charset
*/
public function __construct(Swift_Mime_HeaderSet $headers,
Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_Mime_Grammar $grammar, $charset = null)
{
parent::__construct($headers, $encoder, $cache, $grammar);
$this->setContentType('text/plain');
if (!is_null($charset))
{
$this->setCharset($charset);
}
}
/**
* Set the body of this entity, either as a string, or as an instance of
* {@link Swift_OutputByteStream}.
*
* @param mixed $body
* @param string $contentType optional
* @param string $charset optional
* @param Swift_Mime_MimePart
*/
public function setBody($body, $contentType = null, $charset = null)
{
if (isset($charset))
{
$this->setCharset($charset);
}
$body = $this->_convertString($body);
parent::setBody($body, $contentType);
return $this;
}
/**
* Get the character set of this entity.
*
* @return string
*/
public function getCharset()
{
return $this->_getHeaderParameter('Content-Type', 'charset');
}
/**
* Set the character set of this entity.
*
* @param string $charset
* @param Swift_Mime_MimePart
*/
public function setCharset($charset)
{
$this->_setHeaderParameter('Content-Type', 'charset', $charset);
if ($charset !== $this->_userCharset)
{
$this->_clearCache();
}
$this->_userCharset = $charset;
parent::charsetChanged($charset);
return $this;
}
/**
* Get the format of this entity (i.e. flowed or fixed).
*
* @return string
*/
public function getFormat()
{
return $this->_getHeaderParameter('Content-Type', 'format');
}
/**
* Set the format of this entity (flowed or fixed).
*
* @param string $format
* @param Swift_Mime_MimePart
*/
public function setFormat($format)
{
$this->_setHeaderParameter('Content-Type', 'format', $format);
$this->_userFormat = $format;
return $this;
}
/**
* Test if delsp is being used for this entity.
*
* @return boolean
*/
public function getDelSp()
{
return ($this->_getHeaderParameter('Content-Type', 'delsp') == 'yes')
? true
: false;
}
/**
* Turn delsp on or off for this entity.
*
* @param boolean $delsp
* @param Swift_Mime_MimePart
*/
public function setDelSp($delsp = true)
{
$this->_setHeaderParameter('Content-Type', 'delsp', $delsp ? 'yes' : null);
$this->_userDelSp = $delsp;
return $this;
}
/**
* Get the nesting level of this entity.
*
* @return int
* @see LEVEL_TOP, LEVEL_ALTERNATIVE, LEVEL_MIXED, LEVEL_RELATED
*/
public function getNestingLevel()
{
return $this->_nestingLevel;
}
/**
* Receive notification that the charset has changed on this document, or a
* parent document.
*
* @param string $charset
*/
public function charsetChanged($charset)
{
$this->setCharset($charset);
}
// -- Protected methods
/** Fix the content-type and encoding of this entity */
protected function _fixHeaders()
{
parent::_fixHeaders();
if (count($this->getChildren()))
{
$this->_setHeaderParameter('Content-Type', 'charset', null);
$this->_setHeaderParameter('Content-Type', 'format', null);
$this->_setHeaderParameter('Content-Type', 'delsp', null);
}
else
{
$this->setCharset($this->_userCharset);
$this->setFormat($this->_userFormat);
$this->setDelSp($this->_userDelSp);
}
}
/** Set the nesting level of this entity */
protected function _setNestingLevel($level)
{
$this->_nestingLevel = $level;
}
/** Encode charset when charset is not utf-8 */
protected function _convertString($string)
{
$charset = strtolower($this->getCharset());
if (!in_array($charset, array('utf-8', 'iso-8859-1', "")))
{
// mb_convert_encoding must be the first one to check, since iconv cannot convert some words.
if (function_exists('mb_convert_encoding'))
{
$string = mb_convert_encoding($string, $charset, 'utf-8');
}
else if (function_exists('iconv'))
{
$string = iconv($charset, 'utf-8//TRANSLIT//IGNORE', $string);
}
else
{
throw new Swift_SwiftException('No suitable convert encoding function (use UTF-8 as your harset or install the mbstring or iconv extension).');
}
return $string;
}
return $string;
}
}

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