First commit

This commit is contained in:
Theodotos Andreou 2018-01-14 13:10:16 +00:00
commit c6e2478c40
13918 changed files with 2303184 additions and 0 deletions

View file

@ -0,0 +1,16 @@
CREDITS
=======
eZ Components team
------------------
- Sergey Alexeev
- Sebastian Bergmann
- Jan Borsodi
- Raymond Bosman
- Frederik Holljen
- Kore Nordmann
- Derick Rethans
- Vadym Savchuk
- Tobias Schlitt
- Alexandru Stanoi

View file

@ -0,0 +1,326 @@
1.7 - Monday 29 June 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- No changes
1.7rc1 - Monday 22 June 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an issue with the PEAR reader as sometimes the returned structure is
different.
1.7beta1 - Monday 08 June 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Made sure that we (try) to load the PEAR Registry class so that PEAR doesn't
have to be in autoload.
1.7alpha1 - Tuesday 26 May 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added 'SunOS' to the list of Unices to make finding binaries work on Solaris
as well.
- Implemented issue #13718: Include metadata about installed components that
can be queried to figure out required PHP versions, dependencies and
component versions.
1.6.1 - Monday 09 February 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #14402: Auto detection of external programs (binaries) does not
throw warnings anymore.
1.6 - Monday 05 January 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added a workaround for a segfault in call_user_func() in PHP 5.2.x.
1.6rc1 - Monday 15 December 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Implemented issue #12542: Refactored the ezcBaseFile::findRecursive() method
into the ezcBase::walkRecursive() method so that you can setup your own
callbacks to "do things". The findRecursive() method is now implemented
through this.
- Fixed issue #14091: Incorrect documentation for
ezcBaseConfigurationInitializer.
1.6beta1 - Monday 01 December 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the exception class ezcBaseFunctionalityNotSupportedException.
1.5.2 - Monday 06 October 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an issue in ezcBaseFile::removeRecursive, where the parent directory
could not be written to. We now make sure nothing is deleted until we're sure
everything can be deleted.
1.5.1 - Monday 04 August 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #13370: Infinitive loop in ezcBaseFile::calculateRelativePath().
- Implemented issue #11865: Different development modes.
1.5 - Monday 16 June 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- No changes.
1.5rc1 - Tuesday 10 June 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- No changes
1.5beta1 - Tuesday 27 May 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the ezcBasePersistable interface that can be used to ensure that the
object implementing this interface can be used with PersistentObject and
Search.
1.5alpha2 - Tuesday 13 May 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed a bug in ezcBaseFile::findRecursive that prevented you from passing an
empty array to collect statistics.
- Changed ezcBase::getInstallationPath() so that it always returns a trailing
directory separator.
1.5alpha1 - Monday 07 April 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Implemented issue #8529: Added a by-reference argument to
ezcBaseFile::findRecursive that returns statistsics (count and total size)
of all files that are returned by this function.
- Implemented issue #11506: Added the static method
ezcBase::getInstallationPath().
- Implemented issue #12694: replace reflection test for class type with spl
function.
1.4.1 - Monday 14 January 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #11448: ezc_bootsrap.php uses relative paths.
- Fixed issue #12316: Numbers in own component prefix not possible.
- Fixed issue #12329: ezcBaseFeatures::findExecutableInPath's return value
does not include the extension to the executable at the end on Windows.
- Added an optional argument to the ezcBaseValueException constructor to allow
the exception to be used for non-property/setting type violations as well.
1.4 - Monday 17 December 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- No changes.
1.4rc1 - Wednesday 05 December 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- No changes.
1.4beta1 - Wednesday 28 November 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- No changes.
1.4alpha2 - Monday 29 October 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the ezcBaseFile::copyRecursive() method, to recursively copy files or
directories
- Fixed issue #11540: Problems with ezcFile::findRecursive and
ezcFile::calculateRelativePath on systems where DIRECTORY_SEPERATOR is not
//.
1.4alpha1 - Tuesday 18 September 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the ezcBaseFile class, which was moved from the File component.
- Added the ezcBaseFile::isAbsolutePath() method, which returns whether a path
is absolute or relative.
1.3.1 - Monday 30 July 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #11057: The ezcBaseConfigurationInitializer inteface is not
enforced for callback classes.
1.3 - Monday 02 July 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Documentation fixes and updates.
1.3rc1 - Monday 25 June 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Documentation fixes and updates.
1.3beta2 - Thursday 31 May 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #10704: Autoload fails on class not found. The exception is now
off by default, but can be turned on through the "debug" property of the
ezcBaseAutoloadOptions class. This option class can be set with
ezcBase::setOptions().
1.3beta1 - Monday 07 May 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #8433: ezcBase::getRepositoryDirectories() problems.
- Fixed issue #10583: ezcBaseOptions misses __isset().
- Fixed issue #10666: ezc_bootstrap.php fails on Windows.
- Implemented issue #9569: Add "autoload.php" as 3rd fallback autoload file to
search for.
- Implemented issue #9988: Implement component preloading for better opcode
cache performance.
- Added exception class ezcBaseExtensionNotFoundException to be thrown when an
extension is required but is not found.
- Changed the ezcBaseInit::fetchConfig() method to return the value that was
returned from the callback function.
1.2 - Monday 18 December 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #9658: Checking if $_ENV['PATH'] is set before using it in
ezcBaseFeatures.
- Fixed issue #9780: ezcBaseFeatures throws notice about non-existing array
key "PATH".
- Fixed issue #9819: Let all components deal with the ezcBaseAutoloadException
properly.
- Fixed the exception name for 'ezcBaseDoubleClassRepositoryPrefix' - it was
missing "Exception".
- Implemented issue #9811: If a file for a class can not be found through
autoloading, we now throw the ezcBaseAutoloadException which makes debugging
easier.
- Added the static method ezcBaseFeatures::findExecutableInPath() that searches the
path for the given executable.
- Added the static method ezcBaseFeatures::os() that returns a sanitized
version of the current OS' name.
1.2beta2 - Monday 20 November 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #8507: Two autoload directories with the same basepath don't
work.
- Fixed issue #9390: Classes in external repositories that map to the same
autoload filename of an internal component were added to the external
autoload cache array as well.
1.2beta1 - Tuesday 24 October 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the ezcBaseFeatures class to check whether the current PHP
installation and environment provides features that can be used in the
components.
- Added the ezcBaseInit class that assists you by setting up on-demand
configurations for objects (most notable useful for singleton classes).
- Implemented FR #8508: Display search paths for the autoload files in case of
a missing class.
- Implemented FR #8753: Added the 'Base/ezc_bootstrap.php' file which sets up
the autoload environment for you to facilitate an easier way of starting to
use the eZ components.
1.1.1 - Monday 28 August 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the ezcBaseStruct class from which all structs in all components
should inherit from.
1.1 - Friday 09 June 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed bug #8434: ezcBase autoload system does not handle classes without a
prefix.
- Fixed bug #8435: ezcBase::addClassRepository assumes the ezc way of
structuring files. From now on the path specifying the autoload directory is
*not* relative to the repository directory anymore.
1.1rc1 - Monday 29 May 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed bug #8252: Autoloading for external repositories only works for the
first such class.
1.1beta2 - Tuesday 09 May 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added support for external class repositories. You can now add a class
repository to the autoload mechanism by using the addClassRepository()
method.
- Added a method to return all configured class repositories.
- Added the REMOVE constant to the ezcBaseFileException.
- Added the ezcBaseOptions class that serves as base class for all option
classes in the components.
1.1beta1 - Wednesday 19 April 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Changed the way how files are included when the SVN checkout of the eZ
components was used. This does not affect normal use of the components.
- Fixed class descriptions for the exceptions in the documentation.
1.0 - Monday 30 January 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added HTML escaping of exception messages so that they show up correctly in
a browser. The original message is stored in the originalMessage property
in the exception object.
1.0rc1 - Monday 16 January 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the ezcBaseException that all exceptions in the components library
should descent from.
- Added generic File and IO exceptions that all other components can use
instead of having to reimplement them.
- Added ezcBase::checkDependency() method that allows components to specify
dependencies on either a PHP version or a PHP extension.
1.0beta2 - Wednesday 21 December 2005
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the ezcBasePropertyException that can be used by components to signal
that an property was assigned a value which it does not allows.
1.0beta1 - Tuesday 22 November 2005
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Initial release of this package.

View file

@ -0,0 +1,2 @@
The Base package provides the basic infrastructure that all packages rely on.
Therefore every component relies on this package.

View file

@ -0,0 +1,44 @@
{
"authors": [
{
"name": "Sergey Alexeev"
},
{
"name": "Sebastian Bergmann"
},
{
"name": "Jan Borsodi"
},
{
"name": "Raymond Bosman"
},
{
"name": "Frederik Holljen"
},
{
"name": "Kore Nordmann"
},
{
"name": "Derick Rethans"
},
{
"name": "Vadym Savchuk"
},
{
"name": "Tobias Schlitt"
},
{
"name": "Alexandru Stanoi"
}
],
"autoload": {
"classmap": [
"src"
]
},
"description": "The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.",
"homepage": "https://github.com/zetacomponents",
"license": "apache2",
"name": "zetacomponents/base",
"type": "library"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

View file

@ -0,0 +1,9 @@
Base
====
Purpose
-------
This is the base package of the eZ publish components, offering the basic
support that all Components need. In the first version this will be the
autoload support.

View file

@ -0,0 +1,23 @@
Review Alexandru 2008-05-08
===========================
[X] Regarding feature request #8529 (a du -s implementation). The documentation
for ezcBaseFile::findRecursive() says that you can supply an empty array
as the 4th argument to get the statistics.
If I pass for example $stats which I initialized with array() before, then
I get notices: "Undefined index: count in /home/as/dev/ezcomponents/trunk/Base/src/file.php
on line 139", and the same notice for index "size".
Also the documentation does not mention that you need to pass a variable and not
a value - if I pass array() as the 4th argument I get the error "Cannot pass
parameter 4 by reference"
If I pass $stats which I initialize with null, false or empty string before,
then the function works.
Also all the file recursive tests fail on Windows (slash issues mostly).
[X] Regarding feature request #11506 (method ezcBase::getInstallationPath()). On
Linux it returns the path without any slash at the end, but on Windows (Vista)
it adds a Windows slash at the end.

View file

@ -0,0 +1,656 @@
<?php
/**
* File containing the ezcBase class.
*
* @package Base
* @version //autogentag//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Base class implements the methods needed to use the eZ components.
*
* @package Base
* @version //autogentag//
* @mainclass
*/
class ezcBase
{
/**
* Used for dependency checking, to check for a PHP extension.
*/
const DEP_PHP_EXTENSION = "extension";
/**
* Used for dependency checking, to check for a PHP version.
*/
const DEP_PHP_VERSION = "version";
/**
* Denotes the production mode
*/
const MODE_PRODUCTION = 0;
/**
* Denotes the development mode
*/
const MODE_DEVELOPMENT = 1;
/**
* Indirectly it determines the path where the autoloads are stored.
*
* @var string
*/
private static $libraryMode = "devel";
/**
* Contains the current working directory, which is used when the
* $libraryMode is set to "custom".
*
* @var string
*/
private static $currentWorkingDirectory = null;
/**
* The full path to the autoload directory.
*
* @var string
*/
protected static $packageDir = null;
/**
* Contains which development mode is used. It's "development" by default,
* because of backwards compatibility reasons.
*/
private static $runMode = self::MODE_DEVELOPMENT;
/**
* Stores info with additional paths where autoload files and classes for
* autoloading could be found. Each item of $repositoryDirs looks like
* array( autoloadFileDir, baseDir ). The array key is the prefix belonging
* to classes within that repository - if provided when calling
* addClassRepository(), or an autoincrement integer otherwise.
*
* @var array(string=>array)
*/
protected static $repositoryDirs = array();
/**
* This variable stores all the elements from the autoload arrays. When a
* new autoload file is loaded, their files are added to this array.
*
* @var array(string=>string)
*/
protected static $autoloadArray = array();
/**
* This variable stores all the elements from the autoload arrays for
* external repositories. When a new autoload file is loaded, their files
* are added to this array.
*
* @var array(string=>string)
*/
protected static $externalAutoloadArray = array();
/**
* Options for the ezcBase class.
*
* @var ezcBaseOptions
*/
static private $options;
/**
* Associates an option object with this static class.
*
* @param ezcBaseAutoloadOptions $options
*/
static public function setOptions( ezcBaseAutoloadOptions $options )
{
self::$options = $options;
}
/**
* Tries to autoload the given className. If the className could be found
* this method returns true, otherwise false.
*
* This class caches the requested class names (including the ones who
* failed to load).
*
* @param string $className The name of the class that should be loaded.
*
* @return bool
*/
public static function autoload( $className )
{
ezcBase::setPackageDir();
// Check whether the classname is already in the cached autoloadArray.
if ( array_key_exists( $className, ezcBase::$autoloadArray ) )
{
// Is it registered as 'unloadable'?
if ( ezcBase::$autoloadArray[$className] == false )
{
return false;
}
ezcBase::loadFile( ezcBase::$autoloadArray[$className] );
return true;
}
// Check whether the classname is already in the cached autoloadArray
// for external repositories.
if ( array_key_exists( $className, ezcBase::$externalAutoloadArray ) )
{
// Is it registered as 'unloadable'?
if ( ezcBase::$externalAutoloadArray[$className] == false )
{
return false;
}
ezcBase::loadExternalFile( ezcBase::$externalAutoloadArray[$className] );
return true;
}
// Not cached, so load the autoload from the package.
// Matches the first and optionally the second 'word' from the classname.
$fileNames = array();
if ( preg_match( "/^([a-z0-9]*)([A-Z][a-z0-9]*)([A-Z][a-z0-9]*)?/", $className, $matches ) !== false )
{
$autoloadFile = "";
// Try to match with both names, if available.
switch ( sizeof( $matches ) )
{
case 4:
// check for x_y_autoload.php
$autoloadFile = strtolower( "{$matches[2]}_{$matches[3]}_autoload.php" );
$fileNames[] = $autoloadFile;
if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) )
{
return true;
}
// break intentionally missing.
case 3:
// check for x_autoload.php
$autoloadFile = strtolower( "{$matches[2]}_autoload.php" );
$fileNames[] = $autoloadFile;
if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) )
{
return true;
}
// check for autoload.php
$autoloadFile = 'autoload.php';
$fileNames[] = $autoloadFile;
if ( ezcBase::requireFile( $autoloadFile, $className, $matches[1] ) )
{
return true;
}
break;
}
// Maybe there is another autoload available.
// Register this classname as false.
ezcBase::$autoloadArray[$className] = false;
}
$path = ezcBase::$packageDir . 'autoload/';
$realPath = realpath( $path );
if ( $realPath == '' )
{
// Can not be tested, because if this happens, then the autoload
// environment has not been set-up correctly.
trigger_error( "Couldn't find autoload directory '$path'", E_USER_ERROR );
}
$dirs = self::getRepositoryDirectories();
if ( ezcBase::$options && ezcBase::$options->debug )
{
throw new ezcBaseAutoloadException( $className, $fileNames, $dirs );
}
return false;
}
/**
* Sets the current working directory to $directory.
*
* @param string $directory
*/
public static function setWorkingDirectory( $directory )
{
self::$libraryMode = 'custom';
self::$currentWorkingDirectory = $directory;
}
/**
* Figures out the base path of the eZ Components installation.
*
* It stores the path that it finds in a static member variable. The path
* depends on the installation method of the eZ Components. The SVN version
* has a different path than the PEAR installed version.
*/
protected static function setPackageDir()
{
if ( ezcBase::$packageDir !== null )
{
return;
}
// Get the path to the components.
$baseDir = dirname( __FILE__ );
switch ( ezcBase::$libraryMode )
{
case "custom":
ezcBase::$packageDir = self::$currentWorkingDirectory . '/';
break;
case "devel":
case "tarball":
ezcBase::$packageDir = $baseDir. "/../../";
break;
case "pear";
ezcBase::$packageDir = $baseDir. "/../";
break;
}
}
/**
* Tries to load the autoload array and, if loaded correctly, includes the class.
*
* @param string $fileName Name of the autoload file.
* @param string $className Name of the class that should be autoloaded.
* @param string $prefix The prefix of the class repository.
*
* @return bool True is returned when the file is correctly loaded.
* Otherwise false is returned.
*/
protected static function requireFile( $fileName, $className, $prefix )
{
$autoloadDir = ezcBase::$packageDir . "autoload/";
// We need the full path to the fileName. The method file_exists() doesn't
// automatically check the (php.ini) library paths. Therefore:
// file_exists( "ezc/autoload/$fileName" ) doesn't work.
if ( $prefix === 'ezc' && file_exists( "$autoloadDir$fileName" ) )
{
$array = require( "$autoloadDir$fileName" );
if ( is_array( $array) && array_key_exists( $className, $array ) )
{
// Add the array to the cache, and include the requested file.
ezcBase::$autoloadArray = array_merge( ezcBase::$autoloadArray, $array );
if ( ezcBase::$options !== null && ezcBase::$options->preload && !preg_match( '/Exception$/', $className ) )
{
foreach ( $array as $loadClassName => $file )
{
if ( $loadClassName !== 'ezcBase' && !class_exists( $loadClassName, false ) && !interface_exists( $loadClassName, false ) && !preg_match( '/Exception$/', $loadClassName ) /*&& !class_exists( $loadClassName, false ) && !interface_exists( $loadClassName, false )*/ )
{
ezcBase::loadFile( ezcBase::$autoloadArray[$loadClassName] );
}
}
}
else
{
ezcBase::loadFile( ezcBase::$autoloadArray[$className] );
}
return true;
}
}
// It is not in components autoload/ dir.
// try to search in additional dirs.
foreach ( ezcBase::$repositoryDirs as $repositoryPrefix => $extraDir )
{
if ( gettype( $repositoryPrefix ) === 'string' && $repositoryPrefix !== $prefix )
{
continue;
}
if ( file_exists( $extraDir['autoloadDirPath'] . '/' . $fileName ) )
{
$array = array();
$originalArray = require( $extraDir['autoloadDirPath'] . '/' . $fileName );
// Building paths.
// Resulting path to class definition file consists of:
// path to extra directory with autoload file +
// basePath provided for current extra directory +
// path to class definition file stored in autoload file.
foreach ( $originalArray as $class => $classPath )
{
$array[$class] = $extraDir['basePath'] . '/' . $classPath;
}
if ( is_array( $array ) && array_key_exists( $className, $array ) )
{
// Add the array to the cache, and include the requested file.
ezcBase::$externalAutoloadArray = array_merge( ezcBase::$externalAutoloadArray, $array );
ezcBase::loadExternalFile( ezcBase::$externalAutoloadArray[$className] );
return true;
}
}
}
// Nothing found :-(.
return false;
}
/**
* Loads, require(), the given file name. If we are in development mode,
* "/src/" is inserted into the path.
*
* @param string $file The name of the file that should be loaded.
*/
protected static function loadFile( $file )
{
switch ( ezcBase::$libraryMode )
{
case "devel":
case "tarball":
list( $first, $second ) = explode( '/', $file, 2 );
$file = $first . "/src/" . $second;
break;
case "custom":
list( $first, $second ) = explode( '/', $file, 2 );
// Add the "src/" after the package name.
if ( $first == 'Base' || $first == 'UnitTest' )
{
list( $first, $second ) = explode( '/', $file, 2 );
$file = $first . "/src/" . $second;
}
else
{
list( $first, $second, $third ) = explode( '/', $file, 3 );
$file = $first . '/' . $second . "/src/" . $third;
}
break;
case "pear":
/* do nothing, it's already correct */
break;
}
if ( file_exists( ezcBase::$packageDir . $file ) )
{
require( ezcBase::$packageDir . $file );
}
else
{
// Can not be tested, because if this happens, then one of the
// components has a broken autoload file.
throw new ezcBaseFileNotFoundException( ezcBase::$packageDir.$file );
}
}
/**
* Loads, require(), the given file name from an external package.
*
* @param string $file The name of the file that should be loaded.
*/
protected static function loadExternalFile( $file )
{
if ( file_exists( $file ) )
{
require( $file );
}
else
{
throw new ezcBaseFileNotFoundException( $file );
}
}
/**
* Checks for dependencies on PHP versions or extensions
*
* The function as called by the $component component checks for the $type
* dependency. The dependency $type is compared against the $value. The
* function aborts the script if the dependency is not matched.
*
* @param string $component
* @param int $type
* @param mixed $value
*/
public static function checkDependency( $component, $type, $value )
{
switch ( $type )
{
case self::DEP_PHP_EXTENSION:
if ( extension_loaded( $value ) )
{
return;
}
else
{
// Can not be tested as it would abort the PHP script.
die( "\nThe {$component} component depends on the default PHP extension '{$value}', which is not loaded.\n" );
}
break;
case self::DEP_PHP_VERSION:
$phpVersion = phpversion();
if ( version_compare( $phpVersion, $value, '>=' ) )
{
return;
}
else
{
// Can not be tested as it would abort the PHP script.
die( "\nThe {$component} component depends on the PHP version '{$value}', but the current version is '{$phpVersion}'.\n" );
}
break;
}
}
/**
* Return the list of directories that contain class repositories.
*
* The path to the eZ components directory is always included in the result
* array. Each element in the returned array has the format of:
* packageDirectory => ezcBaseRepositoryDirectory
*
* @return array(string=>ezcBaseRepositoryDirectory)
*/
public static function getRepositoryDirectories()
{
$autoloadDirs = array();
ezcBase::setPackageDir();
$repositoryDir = self::$currentWorkingDirectory ? self::$currentWorkingDirectory : ( realpath( dirname( __FILE__ ) . '/../../' ) );
$autoloadDirs['ezc'] = new ezcBaseRepositoryDirectory( ezcBaseRepositoryDirectory::TYPE_INTERNAL, $repositoryDir, $repositoryDir . "/autoload" );
foreach ( ezcBase::$repositoryDirs as $extraDirKey => $extraDirArray )
{
$repositoryDirectory = new ezcBaseRepositoryDirectory( ezcBaseRepositoryDirectory::TYPE_EXTERNAL, realpath( $extraDirArray['basePath'] ), realpath( $extraDirArray['autoloadDirPath'] ) );
$autoloadDirs[$extraDirKey] = $repositoryDirectory;
}
return $autoloadDirs;
}
/**
* Adds an additional class repository.
*
* Used for adding class repositoryies outside the eZ components to be
* loaded by the autoload system.
*
* This function takes two arguments: $basePath is the base path for the
* whole class repository and $autoloadDirPath the path where autoload
* files for this repository are found. The paths in the autoload files are
* relative to the package directory as specified by the $basePath
* argument. I.e. class definition file will be searched at location
* $basePath + path to the class definition file as stored in the autoload
* file.
*
* addClassRepository() should be called somewhere in code before external classes
* are used.
*
* Example:
* Take the following facts:
* <ul>
* <li>there is a class repository stored in the directory "./repos"</li>
* <li>autoload files for that repository are stored in "./repos/autoloads"</li>
* <li>there are two components in this repository: "Me" and "You"</li>
* <li>the "Me" component has the classes "erMyClass1" and "erMyClass2"</li>
* <li>the "You" component has the classes "erYourClass1" and "erYourClass2"</li>
* </ul>
*
* In this case you would need to create the following files in
* "./repos/autoloads". Please note that the part before _autoload.php in
* the filename is the first part of the <b>classname</b>, not considering
* the all lower-case letter prefix.
*
* "my_autoload.php":
* <code>
* <?php
* return array (
* 'erMyClass1' => 'Me/myclass1.php',
* 'erMyClass2' => 'Me/myclass2.php',
* );
* ?>
* </code>
*
* "your_autoload.php":
* <code>
* <?php
* return array (
* 'erYourClass1' => 'You/yourclass1.php',
* 'erYourClass2' => 'You/yourclass2.php',
* );
* ?>
* </code>
*
* The directory structure for the external repository is then:
* <code>
* ./repos/autoloads/my_autoload.php
* ./repos/autoloads/you_autoload.php
* ./repos/Me/myclass1.php
* ./repos/Me/myclass2.php
* ./repos/You/yourclass1.php
* ./repos/You/yourclass2.php
* </code>
*
* To use this repository with the autoload mechanism you have to use the
* following code:
* <code>
* <?php
* ezcBase::addClassRepository( './repos', './repos/autoloads' );
* $myVar = new erMyClass2();
* ?>
* </code>
*
* @throws ezcBaseFileNotFoundException if $autoloadDirPath or $basePath do not exist.
* @param string $basePath
* @param string $autoloadDirPath
* @param string $prefix
*/
public static function addClassRepository( $basePath, $autoloadDirPath = null, $prefix = null )
{
// check if base path exists
if ( !is_dir( $basePath ) )
{
throw new ezcBaseFileNotFoundException( $basePath, 'base directory' );
}
// calculate autoload path if it wasn't given
if ( is_null( $autoloadDirPath ) )
{
$autoloadDirPath = $basePath . '/autoload';
}
// check if autoload dir exists
if ( !is_dir( $autoloadDirPath ) )
{
throw new ezcBaseFileNotFoundException( $autoloadDirPath, 'autoload directory' );
}
// add info to $repositoryDirs
if ( $prefix === null )
{
$array = array( 'basePath' => $basePath, 'autoloadDirPath' => $autoloadDirPath );
// add info to the list of extra dirs
ezcBase::$repositoryDirs[] = $array;
}
else
{
if ( array_key_exists( $prefix, ezcBase::$repositoryDirs ) )
{
throw new ezcBaseDoubleClassRepositoryPrefixException( $prefix, $basePath, $autoloadDirPath );
}
// add info to the list of extra dirs, and use the prefix to identify the new repository.
ezcBase::$repositoryDirs[$prefix] = array( 'basePath' => $basePath, 'autoloadDirPath' => $autoloadDirPath );
}
}
/**
* Returns the base path of the eZ Components installation
*
* This method returns the base path, including a trailing directory
* separator.
*
* @return string
*/
public static function getInstallationPath()
{
self::setPackageDir();
$path = realpath( self::$packageDir );
if ( substr( $path, -1 ) !== DIRECTORY_SEPARATOR )
{
$path .= DIRECTORY_SEPARATOR;
}
return $path;
}
/**
* Sets the development mode to the one specified.
*
* @param int $runMode
*/
public static function setRunMode( $runMode )
{
if ( !in_array( $runMode, array( ezcBase::MODE_PRODUCTION, ezcBase::MODE_DEVELOPMENT ) ) )
{
throw new ezcBaseValueException( 'runMode', $runMode, 'ezcBase::MODE_PRODUCTION or ezcBase::MODE_DEVELOPMENT' );
}
self::$runMode = $runMode;
}
/**
* Returns the current development mode.
*
* @return int
*/
public static function getRunMode()
{
return self::$runMode;
}
/**
* Returns true when we are in development mode.
*
* @return bool
*/
public static function inDevMode()
{
return self::$runMode == ezcBase::MODE_DEVELOPMENT;
}
/**
* Returns the installation method
*
* Possible return values are 'custom', 'devel', 'tarball' and 'pear'. Only
* 'tarball' and 'pear' are returned for user-installed versions.
*
* @return string
*/
public static function getInstallMethod()
{
return self::$libraryMode;
}
}
?>

View file

@ -0,0 +1,46 @@
<?php
/**
* Autoloader definition for the Base component.
*
* @copyright Copyright (C) 2005-2009 eZ systems as. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @version //autogentag//
* @filesource
* @package Base
*/
return array(
'ezcBaseException' => 'Base/exceptions/exception.php',
'ezcBaseFileException' => 'Base/exceptions/file_exception.php',
'ezcBaseAutoloadException' => 'Base/exceptions/autoload.php',
'ezcBaseDoubleClassRepositoryPrefixException' => 'Base/exceptions/double_class_repository_prefix.php',
'ezcBaseExtensionNotFoundException' => 'Base/exceptions/extension_not_found.php',
'ezcBaseFileIoException' => 'Base/exceptions/file_io.php',
'ezcBaseFileNotFoundException' => 'Base/exceptions/file_not_found.php',
'ezcBaseFilePermissionException' => 'Base/exceptions/file_permission.php',
'ezcBaseFunctionalityNotSupportedException' => 'Base/exceptions/functionality_not_supported.php',
'ezcBaseInitCallbackConfiguredException' => 'Base/exceptions/init_callback_configured.php',
'ezcBaseInitInvalidCallbackClassException' => 'Base/exceptions/invalid_callback_class.php',
'ezcBaseInvalidParentClassException' => 'Base/exceptions/invalid_parent_class.php',
'ezcBasePropertyNotFoundException' => 'Base/exceptions/property_not_found.php',
'ezcBasePropertyPermissionException' => 'Base/exceptions/property_permission.php',
'ezcBaseSettingNotFoundException' => 'Base/exceptions/setting_not_found.php',
'ezcBaseSettingValueException' => 'Base/exceptions/setting_value.php',
'ezcBaseValueException' => 'Base/exceptions/value.php',
'ezcBaseWhateverException' => 'Base/exceptions/whatever.php',
'ezcBaseOptions' => 'Base/options.php',
'ezcBaseStruct' => 'Base/struct.php',
'ezcBase' => 'Base/base.php',
'ezcBaseAutoloadOptions' => 'Base/options/autoload.php',
'ezcBaseConfigurationInitializer' => 'Base/interfaces/configuration_initializer.php',
'ezcBaseFeatures' => 'Base/features.php',
'ezcBaseFile' => 'Base/file.php',
'ezcBaseFileFindContext' => 'Base/structs/file_find_context.php',
'ezcBaseInit' => 'Base/init.php',
'ezcBaseMetaData' => 'Base/metadata.php',
'ezcBaseMetaDataPearReader' => 'Base/metadata/pear.php',
'ezcBaseMetaDataTarballReader' => 'Base/metadata/tarball.php',
'ezcBasePersistable' => 'Base/interfaces/persistable.php',
'ezcBaseRepositoryDirectory' => 'Base/structs/repository_directory.php',
);
?>

View file

@ -0,0 +1,38 @@
<?php
/**
* File containing the ezcBaseAutoloadException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseAutoloadException is thrown whenever a class can not be found with
* the autoload mechanism.
*
* @package Base
* @version //autogen//
*/
class ezcBaseAutoloadException extends ezcBaseException
{
/**
* Constructs a new ezcBaseAutoloadException for the $className that was
* searched for in the autoload files $fileNames from the directories
* specified in $dirs.
*
* @param string $className
* @param array(string) $files
* @param array(ezcBaseRepositoryDirectory) $dirs
*/
function __construct( $className, $files, $dirs )
{
$paths = array();
foreach ( $dirs as $dir )
{
$paths[] = realpath( $dir->autoloadPath );
}
parent::__construct( "Could not find a class to file mapping for '{$className}'. Searched for ". implode( ', ', $files ) . " in: " . implode( ', ', $paths ) );
}
}
?>

View file

@ -0,0 +1,34 @@
<?php
/**
* File containing the ezcBaseDoubleClassRepositoryPrefixException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseDoubleClassRepositoryPrefixException is thrown whenever you try to
* register a class repository with a prefix that has already been added
* before.
*
* @package Base
* @version //autogen//
*/
class ezcBaseDoubleClassRepositoryPrefixException extends ezcBaseException
{
/**
* Constructs a new ezcBaseDoubleClassRepositoryPrefixException for the
* $prefix that points to $basePath with autoload directory
* $autoloadDirPath.
*
* @param string $prefix
* @param string $basePath
* @param string $autoloadDirPath
*/
function __construct( $prefix, $basePath, $autoloadDirPath )
{
parent::__construct( "The class repository in '{$basePath}' (with autoload dir '{$autoloadDirPath}') can not be added because another class repository already uses the prefix '{$prefix}'." );
}
}
?>

View file

@ -0,0 +1,43 @@
<?php
/**
* File containing the ezcBaseException class.
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseException is a container from which all other exceptions in the
* components library descent.
*
* @package Base
* @version //autogen//
*/
abstract class ezcBaseException extends Exception
{
/**
* Original message, before escaping
*/
public $originalMessage;
/**
* Constructs a new ezcBaseException with $message
*
* @param string $message
*/
public function __construct( $message )
{
$this->originalMessage = $message;
if ( php_sapi_name() == 'cli' )
{
parent::__construct( $message );
}
else
{
parent::__construct( htmlspecialchars( $message ) );
}
}
}
?>

View file

@ -0,0 +1,38 @@
<?php
/**
* File containing the ezcBaseExtensionNotFoundException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseExtensionNotFoundException is thrown when a requested PHP extension was not found.
*
* @package Base
* @version //autogen//
*/
class ezcBaseExtensionNotFoundException extends ezcBaseException
{
/**
* Constructs a new ezcBaseExtensionNotFoundException.
*
* @param string $name The name of the extension
* @param string $version The version of the extension
* @param string $message Additional text
*/
function __construct( $name, $version = null, $message = null )
{
if ( $version === null )
{
parent::__construct( "The extension '{$name}' could not be found. {$message}" );
}
else
{
parent::__construct( "The extension '{$name}' with version '{$version}' could not be found. {$message}" );
}
}
}
?>

View file

@ -0,0 +1,25 @@
<?php
/**
* File containing the ezcBaseFileException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseFileException is the exception from which all file related exceptions
* inherit.
*
* @package Base
* @version //autogen//
*/
abstract class ezcBaseFileException extends ezcBaseException
{
const READ = 1;
const WRITE = 2;
const EXECUTE = 4;
const CHANGE = 8;
const REMOVE = 16;
}
?>

View file

@ -0,0 +1,50 @@
<?php
/**
* File containing the ezcBaseFileIoException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseFileIoException is thrown when a problem occurs while writing
* and reading to/from an open file.
*
* @package Base
* @version //autogen//
*/
class ezcBaseFileIoException extends ezcBaseFileException
{
/**
* Constructs a new ezcBaseFileIoException for the file $path.
*
* @param string $path The name of the file.
* @param int $mode The mode of the property that is allowed
* (ezcBaseFileException::READ, ezcBaseFileException::WRITE,
* ezcBaseFileException::EXECUTE or
* ezcBaseFileException::CHANGE).
* @param string $message A string with extra information.
*/
function __construct( $path, $mode, $message = null )
{
switch ( $mode )
{
case ezcBaseFileException::READ:
$operation = "An error occurred while reading from '{$path}'";
break;
case ezcBaseFileException::WRITE:
$operation = "An error occurred while writing to '{$path}'";
break;
}
$messagePart = '';
if ( $message )
{
$messagePart = " ($message)";
}
parent::__construct( "$operation.$messagePart" );
}
}
?>

View file

@ -0,0 +1,43 @@
<?php
/**
* File containing the ezcBaseFileNotFoundException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseFileNotFoundException is thrown when a file or directory was tried to
* be opened, but did not exist.
*
* @package Base
* @version //autogen//
*/
class ezcBaseFileNotFoundException extends ezcBaseFileException
{
/**
* Constructs a new ezcBaseFileNotFoundException.
*
* @param string $path The name of the file.
* @param string $type The type of the file.
* @param string $message A string with extra information.
*/
function __construct( $path, $type = null, $message = null )
{
$typePart = '';
if ( $type )
{
$typePart = "$type ";
}
$messagePart = '';
if ( $message )
{
$messagePart = " ($message)";
}
parent::__construct( "The {$typePart}file '{$path}' could not be found.$messagePart" );
}
}
?>

View file

@ -0,0 +1,63 @@
<?php
/**
* File containing the ezcBaseFilePermissionException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseFilePermissionException is thrown whenever a permission problem with
* a file, directory or stream occurred.
*
* @package Base
* @version //autogen//
*/
class ezcBaseFilePermissionException extends ezcBaseFileException
{
/**
* Constructs a new ezcPropertyPermissionException for the property $name.
*
* @param string $path The name of the file.
* @param int $mode The mode of the property that is allowed
* (ezcBaseFileException::READ, ezcBaseFileException::WRITE,
* ezcBaseFileException::EXECUTE,
* ezcBaseFileException::CHANGE or
* ezcBaseFileException::REMOVE).
* @param string $message A string with extra information.
*/
function __construct( $path, $mode, $message = null )
{
switch ( $mode )
{
case ezcBaseFileException::READ:
$operation = "The file '{$path}' can not be opened for reading";
break;
case ezcBaseFileException::WRITE:
$operation = "The file '{$path}' can not be opened for writing";
break;
case ezcBaseFileException::EXECUTE:
$operation = "The file '{$path}' can not be executed";
break;
case ezcBaseFileException::CHANGE:
$operation = "The permissions for '{$path}' can not be changed";
break;
case ezcBaseFileException::REMOVE:
$operation = "The file '{$path}' can not be removed";
break;
case ( ezcBaseFileException::READ || ezcBaseFileException::WRITE ):
$operation = "The file '{$path}' can not be opened for reading and writing";
break;
}
$messagePart = '';
if ( $message )
{
$messagePart = " ($message)";
}
parent::__construct( "$operation.$messagePart" );
}
}
?>

View file

@ -0,0 +1,31 @@
<?php
/**
* File containing the ezcBaseFunctionalityNotSupportedException class.
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* The ezcBaseFunctionalityNotSupportedException is thrown when a requested
* PHP function was not found.
*
* @package Base
* @version //autogen//
*/
class ezcBaseFunctionalityNotSupportedException extends ezcBaseException
{
/**
* Constructs a new ezcBaseFunctionalityNotSupportedException.
*
* @param string $message The message to throw
* @param string $reason The reason for the exception
*/
function __construct( $message, $reason )
{
parent::__construct( "{$message} is not supported. Reason: {$reason}." );
}
}
?>

View file

@ -0,0 +1,31 @@
<?php
/**
* File containing the ezcBaseInitCallbackConfiguredException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseInitCallbackConfiguredException is thrown when you try to assign a
* callback clasname to an identifier, while there is already a callback class
* configured for this identifier.
*
* @package Base
* @version //autogen//
*/
class ezcBaseInitCallbackConfiguredException extends ezcBaseException
{
/**
* Constructs a new ezcBaseInitCallbackConfiguredException.
*
* @param string $identifier
* @param string $originalCallbackClassName
*/
function __construct( $identifier, $originalCallbackClassName )
{
parent::__construct( "The '{$identifier}' is already configured with callback class '{$originalCallbackClassName}'." );
}
}
?>

View file

@ -0,0 +1,31 @@
<?php
/**
* File containing the ezcBaseInitInvalidCallbackClassException class
*
* @package Configuration
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Exception that is thrown if an invalid class is passed as callback class for
* delayed object configuration.
*
* @package Configuration
* @version //autogen//
*/
class ezcBaseInitInvalidCallbackClassException extends ezcBaseException
{
/**
* Constructs a new ezcBaseInitInvalidCallbackClassException for the $callbackClass.
*
* @param string $callbackClass
* @return void
*/
function __construct( $callbackClass )
{
parent::__construct( "Class '{$callbackClass}' does not exist, or does not implement the 'ezcBaseConfigurationInitializer' interface." );
}
}
?>

View file

@ -0,0 +1,29 @@
<?php
/**
* File containing the ezcBaseInvalidParentClassException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Exception that is thrown if an invalid class is passed as custom class.
*
* @package Base
* @version //autogen//
*/
class ezcBaseInvalidParentClassException extends ezcBaseException
{
/**
* Constructs an ezcBaseInvalidParentClassException for custom class $customClass
*
* @param string $expectedParentClass
* @param string $customClass
*/
function __construct( $expectedParentClass, $customClass )
{
parent::__construct( "Class '{$customClass}' does not exist, or does not inherit from the '{$expectedParentClass}' class." );
}
}
?>

View file

@ -0,0 +1,30 @@
<?php
/**
* File containing the ezcBasePropertyNotFoundException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBasePropertyNotFoundException is thrown whenever a non existent property
* is accessed in the Components library.
*
* @package Base
* @version //autogen//
*/
class ezcBasePropertyNotFoundException extends ezcBaseException
{
/**
* Constructs a new ezcBasePropertyNotFoundException for the property
* $name.
*
* @param string $name The name of the property
*/
function __construct( $name )
{
parent::__construct( "No such property name '{$name}'." );
}
}
?>

View file

@ -0,0 +1,42 @@
<?php
/**
* File containing the ezcPropertyReadOnlyException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBasePropertyPermissionException is thrown whenever a read-only property
* is tried to be changed, or when a write-only property was accessed for reading.
*
* @package Base
* @version //autogen//
*/
class ezcBasePropertyPermissionException extends ezcBaseException
{
/**
* Used when the property is read-only.
*/
const READ = 1;
/**
* Used when the property is write-only.
*/
const WRITE = 2;
/**
* Constructs a new ezcPropertyPermissionException for the property $name.
*
* @param string $name The name of the property.
* @param int $mode The mode of the property that is allowed (::READ or ::WRITE).
*/
function __construct( $name, $mode )
{
parent::__construct( "The property '{$name}' is " .
( $mode == self::READ ? "read" : "write" ) .
"-only." );
}
}
?>

View file

@ -0,0 +1,29 @@
<?php
/**
* File containing the ezcBaseSettingNotFoundException class.
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseSettingNotFoundException is thrown whenever there is a name passed as
* part as the options array to setOptions() for an option that doesn't exist.
*
* @package Base
* @version //autogen//
*/
class ezcBaseSettingNotFoundException extends ezcBaseException
{
/**
* Constructs a new ezcBaseSettingNotFoundException for $settingName.
*
* @param string $settingName The name of the setting that does not exist.
*/
function __construct( $settingName )
{
parent::__construct( "The setting '{$settingName}' is not a valid configuration setting." );
}
}
?>

View file

@ -0,0 +1,42 @@
<?php
/**
* File containing the ezcBaseSettingValueException class.
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseSettingValueExeception is thrown whenever a value to a class'
* configuration option is either of the wrong type, or has a wrong value.
*
* @package Base
* @version //autogen//
*/
class ezcBaseSettingValueException extends ezcBaseException
{
/**
* Constructs a new ezcBaseConfigException
*
* @param string $settingName The name of the setting where something was
* wrong with.
* @param mixed $value The value that the option was tried to be set too.
* @param string $expectedValue A string explaining the allowed type and value range.
*/
function __construct( $settingName, $value, $expectedValue = null )
{
$type = gettype( $value );
if ( in_array( $type, array( 'array', 'object', 'resource' ) ) )
{
$value = serialize( $value );
}
$msg = "The value '{$value}' that you were trying to assign to setting '{$settingName}' is invalid.";
if ( $expectedValue )
{
$msg .= " Allowed values are: " . $expectedValue;
}
parent::__construct( $msg );
}
}
?>

View file

@ -0,0 +1,43 @@
<?php
/**
* File containing the ezcBaseValueException class.
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseValueException is thrown whenever the type or value of the given
* variable is not as expected.
*
* @package Base
* @version //autogen//
*/
class ezcBaseValueException extends ezcBaseException
{
/**
* Constructs a new ezcBaseValueException on the $name variable.
*
* @param string $settingName The name of the setting where something was
* wrong with.
* @param mixed $value The value that the option was tried to be set too.
* @param string $expectedValue A string explaining the allowed type and value range.
* @param string $variableType What type of variable was tried to be set (setting, argument).
*/
function __construct( $settingName, $value, $expectedValue = null, $variableType = 'setting' )
{
$type = gettype( $value );
if ( in_array( $type, array( 'array', 'object', 'resource' ) ) )
{
$value = serialize( $value );
}
$msg = "The value '{$value}' that you were trying to assign to $variableType '{$settingName}' is invalid.";
if ( $expectedValue )
{
$msg .= " Allowed values are: " . $expectedValue . '.';
}
parent::__construct( $msg );
}
}
?>

View file

@ -0,0 +1,40 @@
<?php
/**
* File containing the ezcBaseWhateverException class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcBaseWhateverException is thrown whenever something is so seriously wrong.
*
* If this happens it is not possible to repair anything gracefully. An
* example for this could be, that your eZ components installation has thrown
* far to many exceptions. Whenever you receive an ezcBaseWhateverException, do
* not even try to catch it, but forget your project completely and immediately
* stop coding! ;)
*
* @access private
* @package Base
* @version //autogen//
*/
class ezcBaseWhateverException extends ezcBaseException
{
/**
* Constructs a new ezcBaseWhateverException.
*
* @param string $what What happened?
* @param string $where Where did it happen?
* @param string $who Who is responsible?
* @param string $why Why did is happen?
* @access protected
* @return void
*/
function __construct( $what, $where, $who, $why )
{
parent::__construct( "Thanks for using eZ components. Hope you like it! Greetings from Amos, Derick, El Frederico, Ray and Toby." );
}
}
?>

View file

@ -0,0 +1,40 @@
<?php
/**
* Include file that can be used for a quick setup of the eZ Components.
*
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @version //autogentag//
* @filesource
* @package Base
* @access private
*/
$dir = dirname( __FILE__ );
$dirParts = explode( DIRECTORY_SEPARATOR, $dir );
if ( $dirParts[count( $dirParts ) - 1] === 'src' )
{
$baseDir = join( DIRECTORY_SEPARATOR, array_slice( $dirParts, 0, -2 ) );
require $baseDir . '/Base/src/base.php'; // svn, bundle
}
else if ( $dirParts[count( $dirParts ) - 2] === 'ezc' )
{
$baseDir = join( DIRECTORY_SEPARATOR, array_slice( $dirParts, 0, -2 ) );
require $baseDir . '/ezc/Base/base.php'; // pear
}
else
{
die( "Your environment isn't properly set-up. Please refer to the eZ components documentation at http://components.ez.no/doc ." );
}
/**
* Implements the __autoload mechanism for PHP - which can only be done once
* per request.
*
* @param string $className The name of the class that should be loaded.
*/
function __autoload( $className )
{
ezcBase::autoload( $className );
}
?>

View file

@ -0,0 +1,365 @@
<?php
/**
* File containing the ezcBaseFeatures class.
*
* @package Base
* @version //autogentag//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Provides methods needed to check for features.
*
* Example:
* <code>
* <?php
* echo "supports uid: " . ezcBaseFeatures::supportsUserId() . "\n";
* echo "supports symlink: " . ezcBaseFeatures::supportsSymLink() . "\n";
* echo "supports hardlink: " . ezcBaseFeatures::supportsLink() . "\n";
* echo "has imagemagick identify: " . ezcBaseFeatures::hasImageIdentify() . "\n";
* echo " identify path: " . ezcBaseFeatures::getImageIdentifyExecutable() . "\n";
* echo "has imagemagick convert: " . ezcBaseFeatures::hasImageConvert() . "\n";
* echo " convert path: " . ezcBaseFeatures::getImageConvertExecutable() . "\n";
* echo "has gzip extension: " . ezcBaseFeatures::hasExtensionSupport( 'zlib' ) . "\n";
* echo "has pdo_mysql 1.0.2: " . ezcBaseFeatures::hasExtensionSupport( 'pdo_mysql', '1.0.2' ) . "\n"
* ?>
* </code>
*
* @package Base
* @version //autogentag//
*/
class ezcBaseFeatures
{
/**
* Used to store the path of the ImageMagick convert utility.
*
* It is initialized in the {@link getImageConvertExecutable()} function.
*
* @var string
*/
private static $imageConvert = null;
/**
* Used to store the path of the ImageMagick identify utility.
*
* It is initialized in the {@link getImageIdentifyExecutable()} function.
*
* @var string
*/
private static $imageIdentify = null;
/**
* Used to store the operating system.
*
* It is initialized in the {@link os()} function.
*
* @var string
*/
private static $os = null;
/**
* Determines if hardlinks are supported.
*
* @return bool
*/
public static function supportsLink()
{
return function_exists( 'link' );
}
/**
* Determines if symlinks are supported.
*
* @return bool
*/
public static function supportsSymLink()
{
return function_exists( 'symlink' );
}
/**
* Determines if posix uids are supported.
*
* @return bool
*/
public static function supportsUserId()
{
return function_exists( 'posix_getpwuid' );
}
/**
* Determines if the ImageMagick convert utility is installed.
*
* @return bool
*/
public static function hasImageConvert()
{
return !is_null( self::getImageConvertExecutable() );
}
/**
* Returns the path to the ImageMagick convert utility.
*
* On Linux, Unix,... it will return something like: /usr/bin/convert
* On Windows it will return something like: C:\Windows\System32\convert.exe
*
* @return string
*/
public static function getImageConvertExecutable()
{
if ( !is_null( self::$imageConvert ) )
{
return self::$imageConvert;
}
return ( self::$imageConvert = self::findExecutableInPath( 'convert' ) );
}
/**
* Determines if the ImageMagick identify utility is installed.
*
* @return bool
*/
public static function hasImageIdentify()
{
return !is_null( self::getImageIdentifyExecutable() );
}
/**
* Returns the path to the ImageMagick identify utility.
*
* On Linux, Unix,... it will return something like: /usr/bin/identify
* On Windows it will return something like: C:\Windows\System32\identify.exe
*
* @return string
*/
public static function getImageIdentifyExecutable()
{
if ( !is_null( self::$imageIdentify ) )
{
return self::$imageIdentify;
}
return ( self::$imageIdentify = self::findExecutableInPath( 'identify' ) );
}
/**
* Determines if the specified extension is loaded.
*
* If $version is specified, the specified extension will be tested also
* against the version of the loaded extension.
*
* Examples:
* <code>
* hasExtensionSupport( 'gzip' );
* </code>
* will return true if gzip extension is loaded.
*
* <code>
* hasExtensionSupport( 'pdo_mysql', '1.0.2' );
* </code>
* will return true if pdo_mysql extension is loaded and its version is at least 1.0.2.
*
* @param string $extension
* @param string $version
* @return bool
*/
public static function hasExtensionSupport( $extension, $version = null )
{
if ( is_null( $version ) )
{
return extension_loaded( $extension );
}
return extension_loaded( $extension ) && version_compare( phpversion( $extension ), $version, ">=" ) ;
}
/**
* Determines if the specified function is available.
*
* Examples:
* <code>
* ezcBaseFeatures::hasFunction( 'imagepstext' );
* </code>
* will return true if support for Type 1 fonts is available with your GD
* extension.
*
* @param string $functionName
* @return bool
*/
public static function hasFunction( $functionName )
{
return function_exists( $functionName );
}
/**
* Returns if a given class exists.
* Checks for a given class name and returns if this class exists or not.
* Catches the ezcBaseAutoloadException and returns false, if it was thrown.
*
* @param string $className The class to check for.
* @param bool $autoload True to use __autoload(), otherwise false.
* @return bool True if the class exists. Otherwise false.
*/
public static function classExists( $className, $autoload = true )
{
try
{
if ( class_exists( $className, $autoload ) )
{
return true;
}
return false;
}
catch ( ezcBaseAutoloadException $e )
{
return false;
}
}
/**
* Returns the operating system on which PHP is running.
*
* This method returns a sanitized form of the OS name, example
* return values are "Windows", "Mac", "Linux" and "FreeBSD". In
* all other cases it returns the value of the internal PHP constant
* PHP_OS.
*
* @return string
*/
public static function os()
{
if ( is_null( self::$os ) )
{
$uname = php_uname( 's' );
if ( substr( $uname, 0, 7 ) == 'Windows' )
{
self::$os = 'Windows';
}
elseif ( substr( $uname, 0, 3 ) == 'Mac' )
{
self::$os = 'Mac';
}
elseif ( strtolower( $uname ) == 'linux' )
{
self::$os = 'Linux';
}
elseif ( strtolower( substr( $uname, 0, 7 ) ) == 'freebsd' )
{
self::$os = 'FreeBSD';
}
else
{
self::$os = PHP_OS;
}
}
return self::$os;
}
/**
* Returns the path of the specified executable, if it can be found in the system's path.
*
* It scans the PATH enviroment variable based on the OS to find the
* $fileName. For Windows, the path is with \, not /. If $fileName is not
* found, it returns null.
*
* @todo consider using getenv( 'PATH' ) instead of $_ENV['PATH']
* (but that won't work under IIS)
*
* @param string $fileName
* @return string
*/
public static function findExecutableInPath( $fileName )
{
if ( array_key_exists( 'PATH', $_ENV ) )
{
$envPath = trim( $_ENV['PATH'] );
}
else if ( ( $envPath = getenv( 'PATH' ) ) !== false )
{
$envPath = trim( $envPath );
}
if ( is_string( $envPath ) && strlen( trim( $envPath ) ) == 0 )
{
$envPath = false;
}
switch ( self::os() )
{
case 'Unix':
case 'FreeBSD':
case 'Mac':
case 'MacOS':
case 'Darwin':
case 'Linux':
case 'SunOS':
if ( $envPath )
{
$dirs = explode( ':', $envPath );
foreach ( $dirs as $dir )
{
// The @-operator is used here mainly to avoid
// open_basedir warnings. If open_basedir (or any other
// circumstance) prevents the desired file from being
// accessed, it is fine for file_exists() to return
// false, since it is useless for use then, anyway.
if ( file_exists( "{$dir}/{$fileName}" ) )
{
return "{$dir}/{$fileName}";
}
}
}
// The @-operator is used here mainly to avoid open_basedir
// warnings. If open_basedir (or any other circumstance)
// prevents the desired file from being accessed, it is fine
// for file_exists() to return false, since it is useless for
// use then, anyway.
elseif ( @file_exists( "./{$fileName}" ) )
{
return $fileName;
}
break;
case 'Windows':
if ( $envPath )
{
$dirs = explode( ';', $envPath );
foreach ( $dirs as $dir )
{
// The @-operator is used here mainly to avoid
// open_basedir warnings. If open_basedir (or any other
// circumstance) prevents the desired file from being
// accessed, it is fine for file_exists() to return
// false, since it is useless for use then, anyway.
if ( @file_exists( "{$dir}\\{$fileName}.exe" ) )
{
return "{$dir}\\{$fileName}.exe";
}
}
}
// The @-operator is used here mainly to avoid open_basedir
// warnings. If open_basedir (or any other circumstance)
// prevents the desired file from being accessed, it is fine
// for file_exists() to return false, since it is useless for
// use then, anyway.
elseif ( @file_exists( "{$fileName}.exe" ) )
{
return "{$fileName}.exe";
}
break;
}
return null;
}
/**
* Reset the cached information.
*
* @return void
* @access private
* @ignore
*/
public static function reset()
{
self::$imageIdentify = null;
self::$imageConvert = null;
self::$os = null;
}
}
?>

View file

@ -0,0 +1,495 @@
<?php
/**
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @version //autogentag//
* @filesource
* @package Base
*/
/**
* Provides a selection of static independent methods to provide functionality
* for file and file system handling.
*
* This example shows how to use the findRecursive method:
* <code>
* <?php
* // lists all the files under /etc (including subdirectories) that end in
* // .conf
* $confFiles = ezcBaseFile::findRecursive( "/etc", array( '@\.conf$@' ) );
*
* // lists all autoload files in the components source tree and excludes the
* // ones in the autoload subdirectory. Statistics are returned in the $stats
* // variable which is passed by reference.
* $files = ezcBaseFile::findRecursive(
* "/dat/dev/ezcomponents",
* array( '@src/.*_autoload.php$@' ),
* array( '@/autoload/@' ),
* $stats
* );
*
* // lists all binaries in /bin except the ones starting with a "g"
* $data = ezcBaseFile::findRecursive( "/bin", array(), array( '@^/bin/g@' ) );
* ?>
* </code>
*
* @package Base
* @version //autogentag//
* @mainclass
*/
class ezcBaseFile
{
/**
* This is the callback used by findRecursive to collect data.
*
* This callback method works together with walkRecursive() and is called
* for every file/and or directory. The $context is a callback specific
* container in which data can be stored and shared between the different
* calls to the callback function. The walkRecursive() function also passes
* in the full absolute directory in $sourceDir, the filename in $fileName
* and file information (such as size, modes, types) as an array as
* returned by PHP's stat() in the $fileInfo parameter.
*
* @param ezcBaseFileFindContext $context
* @param string $sourceDir
* @param string $fileName
* @param array(stat) $fileInfo
*/
static protected function findRecursiveCallback( ezcBaseFileFindContext $context, $sourceDir, $fileName, $fileInfo )
{
// ignore if we have a directory
if ( $fileInfo['mode'] & 0x4000 )
{
return;
}
// update the statistics
$context->elements[] = $sourceDir . DIRECTORY_SEPARATOR . $fileName;
$context->count++;
$context->size += $fileInfo['size'];
}
/**
* Walks files and directories recursively on a file system
*
* This method walks over a directory and calls a callback from every file
* and directory it finds. You can use $includeFilters to include only
* specific files, and $excludeFilters to exclude certain files from being
* returned. The function will always go into subdirectories even if the
* entry would not have passed the filters.
*
* The callback is passed in the $callback parameter, and the
* $callbackContext will be send to the callback function/method as
* parameter so that you can store data in there that persists with all the
* calls and recursive calls to this method. It's up to the callback method
* to do something useful with this. The callback function's parameters are
* in order:
*
* <ul>
* <li>ezcBaseFileFindContext $context</li>
* <li>string $sourceDir</li>
* <li>string $fileName</li>
* <li>array(stat) $fileInfo</li>
* </ul>
*
* See {@see findRecursiveCallback()} for an example of a callback function.
*
* Filters are regular expressions and are therefore required to have
* starting and ending delimiters. The Perl Compatible syntax is used as
* regular expression language.
*
* @param string $sourceDir
* @param array(string) $includeFilters
* @param array(string) $excludeFilters
* @param callback $callback
* @param mixed $callbackContext
*
* @throws ezcBaseFileNotFoundException if the $sourceDir directory is not
* a directory or does not exist.
* @throws ezcBaseFilePermissionException if the $sourceDir directory could
* not be opened for reading.
* @return array
*/
static public function walkRecursive( $sourceDir, array $includeFilters = array(), array $excludeFilters = array(), $callback, &$callbackContext )
{
if ( !is_dir( $sourceDir ) )
{
throw new ezcBaseFileNotFoundException( $sourceDir, 'directory' );
}
$elements = array();
$d = @dir( $sourceDir );
if ( !$d )
{
throw new ezcBaseFilePermissionException( $sourceDir, ezcBaseFileException::READ );
}
while ( ( $entry = $d->read() ) !== false )
{
if ( $entry == '.' || $entry == '..' )
{
continue;
}
$fileInfo = @stat( $sourceDir . DIRECTORY_SEPARATOR . $entry );
if ( !$fileInfo )
{
$fileInfo = array( 'size' => 0, 'mode' => 0 );
}
if ( $fileInfo['mode'] & 0x4000 )
{
// We need to ignore the Permission exceptions here as it can
// be normal that a directory can not be accessed. We only need
// the exception if the top directory could not be read.
try
{
call_user_func_array( $callback, array( $callbackContext, $sourceDir, $entry, $fileInfo ) );
$subList = self::walkRecursive( $sourceDir . DIRECTORY_SEPARATOR . $entry, $includeFilters, $excludeFilters, $callback, $callbackContext );
$elements = array_merge( $elements, $subList );
}
catch ( ezcBaseFilePermissionException $e )
{
}
}
else
{
// By default a file is included in the return list
$ok = true;
// Iterate over the $includeFilters and prohibit the file from
// being returned when atleast one of them does not match
foreach ( $includeFilters as $filter )
{
if ( !preg_match( $filter, $sourceDir . DIRECTORY_SEPARATOR . $entry ) )
{
$ok = false;
break;
}
}
// Iterate over the $excludeFilters and prohibit the file from
// being returns when atleast one of them matches
foreach ( $excludeFilters as $filter )
{
if ( preg_match( $filter, $sourceDir . DIRECTORY_SEPARATOR . $entry ) )
{
$ok = false;
break;
}
}
// If everything's allright, call the callback and add the
// entry to the elements array
if ( $ok )
{
call_user_func( $callback, $callbackContext, $sourceDir, $entry, $fileInfo );
$elements[] = $sourceDir . DIRECTORY_SEPARATOR . $entry;
}
}
}
sort( $elements );
return $elements;
}
/**
* Finds files recursively on a file system
*
* With this method you can scan the file system for files. You can use
* $includeFilters to include only specific files, and $excludeFilters to
* exclude certain files from being returned. The function will always go
* into subdirectories even if the entry would not have passed the filters.
* It uses the {@see walkRecursive()} method to do the actually recursion.
*
* Filters are regular expressions and are therefore required to have
* starting and ending delimiters. The Perl Compatible syntax is used as
* regular expression language.
*
* If you pass an empty array to the $statistics argument, the function
* will in details about the number of files found into the 'count' array
* element, and the total filesize in the 'size' array element. Because this
* argument is passed by reference, you *have* to pass a variable and you
* can not pass a constant value such as "array()".
*
* @param string $sourceDir
* @param array(string) $includeFilters
* @param array(string) $excludeFilters
* @param array() $statistics
*
* @throws ezcBaseFileNotFoundException if the $sourceDir directory is not
* a directory or does not exist.
* @throws ezcBaseFilePermissionException if the $sourceDir directory could
* not be opened for reading.
* @return array
*/
static public function findRecursive( $sourceDir, array $includeFilters = array(), array $excludeFilters = array(), &$statistics = null )
{
// init statistics array
if ( !is_array( $statistics ) || !array_key_exists( 'size', $statistics ) || !array_key_exists( 'count', $statistics ) )
{
$statistics['size'] = 0;
$statistics['count'] = 0;
}
// create the context, and then start walking over the array
$context = new ezcBaseFileFindContext;
self::walkRecursive( $sourceDir, $includeFilters, $excludeFilters, array( 'ezcBaseFile', 'findRecursiveCallback' ), $context );
// collect the statistics
$statistics['size'] = $context->size;
$statistics['count'] = $context->count;
// return the found and pattern-matched files
sort( $context->elements );
return $context->elements;
}
/**
* Removes files and directories recursively from a file system
*
* This method recursively removes the $directory and all its contents.
* You should be <b>extremely</b> careful with this method as it has the
* potential to erase everything that the current user has access to.
*
* @param string $directory
*/
static public function removeRecursive( $directory )
{
$sourceDir = realpath( $directory );
if ( !$sourceDir )
{
throw new ezcBaseFileNotFoundException( $directory, 'directory' );
}
$d = @dir( $sourceDir );
if ( !$d )
{
throw new ezcBaseFilePermissionException( $directory, ezcBaseFileException::READ );
}
// check if we can remove the dir
$parentDir = realpath( $directory . DIRECTORY_SEPARATOR . '..' );
if ( !is_writable( $parentDir ) )
{
throw new ezcBaseFilePermissionException( $parentDir, ezcBaseFileException::WRITE );
}
// loop over contents
while ( ( $entry = $d->read() ) !== false )
{
if ( $entry == '.' || $entry == '..' )
{
continue;
}
if ( is_dir( $sourceDir . DIRECTORY_SEPARATOR . $entry ) )
{
self::removeRecursive( $sourceDir . DIRECTORY_SEPARATOR . $entry );
}
else
{
if ( @unlink( $sourceDir . DIRECTORY_SEPARATOR . $entry ) === false )
{
throw new ezcBaseFilePermissionException( $directory . DIRECTORY_SEPARATOR . $entry, ezcBaseFileException::REMOVE );
}
}
}
$d->close();
rmdir( $sourceDir );
}
/**
* Recursively copy a file or directory.
*
* Recursively copy a file or directory in $source to the given
* destination. If a depth is given, the operation will stop, if the given
* recursion depth is reached. A depth of -1 means no limit, while a depth
* of 0 means, that only the current file or directory will be copied,
* without any recursion.
*
* You may optionally define modes used to create files and directories.
*
* @throws ezcBaseFileNotFoundException
* If the $sourceDir directory is not a directory or does not exist.
* @throws ezcBaseFilePermissionException
* If the $sourceDir directory could not be opened for reading, or the
* destination is not writeable.
*
* @param string $source
* @param string $destination
* @param int $depth
* @param int $dirMode
* @param int $fileMode
* @return void
*/
static public function copyRecursive( $source, $destination, $depth = -1, $dirMode = 0775, $fileMode = 0664 )
{
// Check if source file exists at all.
if ( !is_file( $source ) && !is_dir( $source ) )
{
throw new ezcBaseFileNotFoundException( $source );
}
// Destination file should NOT exist
if ( is_file( $destination ) || is_dir( $destination ) )
{
throw new ezcBaseFilePermissionException( $destination, ezcBaseFileException::WRITE );
}
// Skip non readable files in source directory
if ( !is_readable( $source ) )
{
return;
}
// Copy
if ( is_dir( $source ) )
{
mkdir( $destination );
// To ignore umask, umask() should not be changed with
// multithreaded servers...
chmod( $destination, $dirMode );
}
elseif ( is_file( $source ) )
{
copy( $source, $destination );
chmod( $destination, $fileMode );
}
if ( ( $depth === 0 ) ||
( !is_dir( $source ) ) )
{
// Do not recurse (any more)
return;
}
// Recurse
$dh = opendir( $source );
while ( ( $file = readdir( $dh ) ) !== false )
{
if ( ( $file === '.' ) ||
( $file === '..' ) )
{
continue;
}
self::copyRecursive(
$source . '/' . $file,
$destination . '/' . $file,
$depth - 1, $dirMode, $fileMode
);
}
}
/**
* Calculates the relative path of the file/directory '$path' to a given
* $base path.
*
* $path and $base should be fully absolute paths. This function returns the
* answer of "How do I go from $base to $path". If the $path and $base are
* the same path, the function returns '.'. This method does not touch the
* filesystem.
*
* @param string $path
* @param string $base
* @return string
*/
static public function calculateRelativePath( $path, $base )
{
// Sanitize the paths to use the correct directory separator for the platform
$path = strtr( $path, '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR );
$base = strtr( $base, '\\/', DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR );
$base = explode( DIRECTORY_SEPARATOR, $base );
$path = explode( DIRECTORY_SEPARATOR, $path );
// If the paths are the same we return
if ( $base === $path )
{
return '.';
}
$result = '';
$pathPart = array_shift( $path );
$basePart = array_shift( $base );
while ( $pathPart == $basePart )
{
$pathPart = array_shift( $path );
$basePart = array_shift( $base );
}
if ( $pathPart != null )
{
array_unshift( $path, $pathPart );
}
if ( $basePart != null )
{
array_unshift( $base, $basePart );
}
$result = str_repeat( '..' . DIRECTORY_SEPARATOR, count( $base ) );
// prevent a trailing DIRECTORY_SEPARATOR in case there is only a ..
if ( count( $path ) == 0 )
{
$result = substr( $result, 0, -strlen( DIRECTORY_SEPARATOR ) );
}
$result .= join( DIRECTORY_SEPARATOR, $path );
return $result;
}
/**
* Returns whether the passed $path is an absolute path, giving the current $os.
*
* With the $os parameter you can tell this function to use the semantics
* for a different operating system to determine whether a path is
* absolute. The $os argument defaults to the OS that the script is running
* on.
*
* @param string $path
* @param string $os
* @return bool
*/
public static function isAbsolutePath( $path, $os = null )
{
if ( $os === null )
{
$os = ezcBaseFeatures::os();
}
// Stream wrapper like phar can also be considered absolute paths
if ( preg_match( '(^[a-z]{3,}://)S', $path ) )
{
return true;
}
switch ( $os )
{
case 'Windows':
// Sanitize the paths to use the correct directory separator for the platform
$path = strtr( $path, '\\/', '\\\\' );
// Absolute paths with drive letter: X:\
if ( preg_match( '@^[A-Z]:\\\\@i', $path ) )
{
return true;
}
// Absolute paths with network paths: \\server\share\
if ( preg_match( '@^\\\\\\\\[A-Z]+\\\\[^\\\\]@i', $path ) )
{
return true;
}
break;
case 'Mac':
case 'Linux':
case 'FreeBSD':
default:
// Sanitize the paths to use the correct directory separator for the platform
$path = strtr( $path, '\\/', '//' );
if ( $path[0] == '/' )
{
return true;
}
}
return false;
}
}
?>

View file

@ -0,0 +1,125 @@
<?php
/**
* File containing the ezcBaseInit class.
*
* @package Base
* @version //autogentag//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Provides a method to implement delayed initialization of objects.
*
* With the methods in this class you can implement callbacks to configure
* singleton classes. In order to do so you will have to change the
* getInstance() method of your singleton class to include a call to
* ezcBaseInit::fetchConfig() as in the following example:
*
* <code>
* <?php
* public static function getInstance()
* {
* if ( is_null( self::$instance ) )
* {
* self::$instance = new ezcConfigurationmanager();
* ezcBaseInit::fetchConfig( 'ezcInitConfigurationManager', self::$instance );
* }
* return self::$instance;
* }
* ?>
* </code>
*
* You will also need to configure which callback class to call. This you do
* with the ezcBaseInit::setCallback() method. The following examples sets the
* callback classname for the configuration identifier
* 'ezcInitConfigurationManager' to 'cfgConfigurationManager':
*
* <code>
* <?php
* ezcBaseInit::setCallback( 'ezcInitConfigurationManager', 'cfgConfigurationManager' );
* ?>
* </code>
*
* The class 'cfgConfigurationManager' is required to implement the
* ezcBaseConfigurationInitializer interface, which defines only one method:
* configureObject(). An example on how to implement such a class could be:
*
* <code>
* <?php
* class cfgConfigurationManager implements ezcBaseConfigurationInitializer
* {
* static public function configureObject( ezcConfigurationManager $cfgManagerObject )
* {
* $cfgManagerObject->init( 'ezcConfigurationIniReader', 'settings', array( 'useComments' => true ) );
* }
* }
* ?>
* </code>
*
* Of course the implementation of this callback class is up to the application
* developer that uses the component (in this example the Configuration
* component's class ezcConfigurationManager).
*
* @package Base
* @version //autogentag//
*/
class ezcBaseInit
{
/**
* Contains the callback where the identifier is the key of the array, and the classname to callback to the value.
*
* @var array(string=>string)
*/
static private $callbackMap = array();
/**
* Adds the classname $callbackClassname as callback for the identifier $identifier.
*
* @param string $identifier
* @param string $callbackClassname
*/
public static function setCallback( $identifier, $callbackClassname )
{
if ( array_key_exists( $identifier, self::$callbackMap ) )
{
throw new ezcBaseInitCallbackConfiguredException( $identifier, self::$callbackMap[$identifier] );
}
else
{
// Check if the passed classname actually exists
if ( !ezcBaseFeatures::classExists( $callbackClassname, true ) )
{
throw new ezcBaseInitInvalidCallbackClassException( $callbackClassname );
}
// Check if the passed classname actually implements the interface.
if ( !in_array( 'ezcBaseConfigurationInitializer', class_implements( $callbackClassname ) ) )
{
throw new ezcBaseInitInvalidCallbackClassException( $callbackClassname );
}
self::$callbackMap[$identifier] = $callbackClassname;
}
}
/**
* Uses the configured callback belonging to $identifier to configure the $object.
*
* The method will return the return value of the callback method, or null
* in case there was no callback set for the specified $identifier.
*
* @param string $identifier
* @param object $object
* @return mixed
*/
public static function fetchConfig( $identifier, $object )
{
if ( isset( self::$callbackMap[$identifier] ) )
{
$callbackClassname = self::$callbackMap[$identifier];
return call_user_func( array( $callbackClassname, 'configureObject' ), $object );
}
return null;
}
}
?>

View file

@ -0,0 +1,32 @@
<?php
/**
* File containing the ezcBaseConfigurationInitializer class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* This class provides the interface that classes need to implement to act as
* an callback initializer class to work with the delayed initialization
* mechanism.
*
* @package Base
* @version //autogen//
*/
interface ezcBaseConfigurationInitializer
{
/**
* Configures the given object, or returns the proper object depending on
* the given identifier.
*
* In case a string identifier was given, it should return the associated
* object, in case an object was given the method should return null.
*
* @param string|object $object
* @return mixed
*/
static public function configureObject( $object );
}
?>

View file

@ -0,0 +1,40 @@
<?php
/**
* File containing the ezcBasePersistable interface
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* This class provides the interface that classes need to implement to be able
* to be used by the PersistentObject and Search components.
*
* @package Base
* @version //autogen//
*/
interface ezcBasePersistable
{
/**
* The constructor for the object needs to be able to accept no arguments.
*
* The data is later set through the setState() method.
*/
public function __construct();
/**
* Returns all the object's properties so that they can be stored or indexed.
*
* @return array(string=>mixed)
*/
public function getState();
/**
* Accepts an array containing data for one or more of the class' properties.
*
* @param array $properties
*/
public function setState( array $properties );
}
?>

View file

@ -0,0 +1,120 @@
<?php
/**
* File containing the ezcBaseMetaData class.
*
* @package Base
* @version //autogentag//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Base class implements ways of fetching information about the installed
* eZ Components. It knows whether to use the PEAR registry or the bundled XML
* file, depending on how eZ Components is installed.
*
* @package Base
* @version //autogentag//
* @mainclass
*/
class ezcBaseMetaData
{
/**
* Creates a ezcBaseMetaData object
*
* The sole parameter $installMethod should only be used if you are really
* sure that you need to use it. It is mostly there to make testing at
* least slightly possible. Again, do not set it unless instructed.
*
* @param string $installMethod
*/
public function __construct( $installMethod = NULL )
{
$installMethod = $installMethod !== NULL ? $installMethod : ezcBase::getInstallMethod();
// figure out which reader to use
switch ( $installMethod )
{
case 'tarball':
$this->reader = new ezcBaseMetaDataTarballReader;
break;
case 'pear':
$this->reader = new ezcBaseMetaDataPearReader;
break;
default:
throw new ezcBaseMetaDataReaderException( "Unknown install method '$installMethod'." );
break;
}
}
/**
* Returns the version string for the installed eZ Components bundle.
*
* A version string such as "2008.2.2" is returned.
*
* @return string
*/
public function getBundleVersion()
{
return $this->reader->getBundleVersion();
}
/**
* Returns a PHP version string that describes the required PHP version for
* this installed eZ Components bundle.
*
* @return string
*/
public function getRequiredPhpVersion()
{
return $this->reader->getRequiredPhpVersion();
}
/**
* Returns whether $componentName is installed
*
* If installed with PEAR, it checks the PEAR registry whether the
* component is there. In case the tarball installation method is used, it
* will return true for every component that exists (because all of them
* are then available).
*
* @return bool
*/
public function isComponentInstalled( $componentName )
{
return $this->reader->isComponentInstalled( $componentName );
}
/**
* Returns the version string of the available $componentName or false when
* the component is not installed.
*
* @return string
*/
public function getComponentVersion( $componentName )
{
return $this->reader->getComponentVersion( $componentName );
}
/**
* Returns a list of components that $componentName depends on.
*
* If $componentName is left empty, all installed components are returned.
*
* The returned array has as keys the component names, and as values the
* version of the components.
*
* @return array(string=>string).
*/
public function getComponentDependencies( $componentName = null )
{
if ( $componentName === null )
{
return $this->reader->getComponentDependencies();
}
else
{
return $this->reader->getComponentDependencies( $componentName );
}
}
}
?>

View file

@ -0,0 +1,129 @@
<?php
/**
* File containing the ezcBaseMetaDataPearReader class.
*
* @package Base
* @version //autogentag//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
@require 'PEAR/Registry.php';
/**
* Base class implements ways of fetching information about the installed
* eZ Components when installed as tarball.
*
* Note: there are lots of @ used here, because PEAR still lives in the stone
* age with their PHP 3 code and general liberal use of throwing warnings and
* notices.
*
* @package Base
* @version //autogentag//
* @mainclass
*/
class ezcBaseMetaDataPearReader
{
/**
* Stores the PEAR_Registry to query for information
*
* @var PEAR_Registry
*/
private $registry;
/**
* Creates the reader object and initialized the registry for querying
*/
public function __construct()
{
@$this->registry = new PEAR_Registry;
}
/**
* Returns the version string for the installed eZ Components bundle.
*
* A version string such as "2008.2.2" is returned.
*
* @return string
*/
public function getBundleVersion()
{
@$packageInfo = $this->registry->packageInfo( 'ezcomponents', null, 'components.ez.no' );
return $packageInfo['version']['release'];
}
/**
* Returns a PHP version string that describes the required PHP version for
* this installed eZ Components bundle.
*
* @return string
*/
public function getRequiredPhpVersion()
{
@$packageInfo = $this->registry->packageInfo( 'ezcomponents', null, 'components.ez.no' );
if ( array_key_exists( 'required', $packageInfo['dependencies'] ) )
{
return $packageInfo['dependencies']['required']['php']['min'];
}
return $packageInfo['dependencies']['php']['min'];
}
/**
* Returns whether $componentName is installed
*
* Checks the PEAR registry whether the component is there.
*
* @return bool
*/
public function isComponentInstalled( $componentName )
{
@$packageInfo = $this->registry->packageInfo( $componentName, null, 'components.ez.no' );
return is_array( $packageInfo );
}
/**
* Returns the version string of the available $componentName or false when
* the component is not installed.
*
* @return string
*/
public function getComponentVersion( $componentName )
{
@$packageInfo = $this->registry->packageInfo( $componentName, null, 'components.ez.no' );
$release = $packageInfo['version']['release'];
return $release === null ? false : $release;
}
/**
* Returns a list of components that $componentName depends on.
*
* If $componentName is left empty, all installed components are returned.
*
* The returned array has as keys the component names, and as values the
* version of the components.
*
* @return array(string=>string).
*/
public function getComponentDependencies( $componentName = 'ezcomponents' )
{
@$packageInfo = $this->registry->packageInfo( $componentName, 'dependencies', 'components.ez.no' );
if ( isset( $packageInfo['required']['package'] ) )
{
$deps = array();
if ( isset( $packageInfo['required']['package']['name'] ) )
{
$deps[$packageInfo['required']['package']['name']] = $packageInfo['required']['package']['min'];
}
else
{
foreach ( $packageInfo['required']['package'] as $package )
{
$deps[$package['name']] = $package['min'];
}
}
return $deps;
}
return array();
}
}
?>

View file

@ -0,0 +1,153 @@
<?php
/**
* File containing the ezcBaseMetaDataTarballReader class.
*
* @package Base
* @version //autogentag//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Base class implements ways of fetching information about the installed
* eZ Components when installed as tarball.
*
* @package Base
* @version //autogentag//
* @mainclass
*/
class ezcBaseMetaDataTarballReader
{
/**
* Contains the handler to the XML file containing the release information.
* @var SimpleXmlElement
*/
private $xml;
/**
* Creates the reader object and opens the release-info file.
*/
public function __construct()
{
$filename = dirname( __FILE__ ) . '/../../../release-info.xml';
$this->xml = simplexml_load_file( $filename );
}
/**
* Returns the version string for the installed eZ Components bundle.
*
* A version string such as "2008.2.2" is returned.
*
* @return string
*/
public function getBundleVersion()
{
return (string) $this->xml->version;
}
/**
* Returns a PHP version string that describes the required PHP version for
* this installed eZ Components bundle.
*
* @return string
*/
public function getRequiredPhpVersion()
{
return (string) $this->xml->deps->php;
}
/**
* Returns whether $componentName is installed
*
* Returns true for every component that exists (because all of them are
* then available).
*
* @return bool
*/
public function isComponentInstalled( $componentName )
{
$root = $this->xml->deps->packages->package;
foreach ( $root as $package )
{
if ( (string) $package['name'] == $componentName )
{
return true;
}
}
return false;
}
/**
* Returns the version string of the available $componentName or false when
* the component is not installed.
*
* @return string
*/
public function getComponentVersion( $componentName )
{
$root = $this->xml->deps->packages->package;
foreach ( $root as $package )
{
if ( (string) $package['name'] == $componentName )
{
return (string) $package['version'];
}
}
return false;
}
/**
* Returns a list of components that $componentName depends on.
*
* If $componentName is left empty, all installed components are returned.
*
* The returned array has as keys the component names, and as values the
* version of the components. It returns null of the $componentName
* is not found.
*
* @return array(string=>string).
*/
public function getComponentDependencies( $componentName = null )
{
$baseVersion = false;
$root = $this->xml->deps->packages;
$found = $componentName === null ? true : false;
// in case $componentName != null, we loop through all the components
// in the file, and figure out the new root that we can list dependency
// packages from.
foreach ( $root->package as $package )
{
if ( (string) $package['name'] == 'Base' )
{
$baseVersion = $package['version'];
}
if ( !$found && (string) $package['name'] == $componentName )
{
$root = $package->deps;
$found = true;
}
}
if ( !$found )
{
return null;
}
// We always add the Base dependency even though it's not in the dependency file.
$deps = array();
$deps['Base'] = (string) $baseVersion;
if ( !isset( $root->package ) )
{
return $deps;
}
foreach ( $root->package as $package )
{
$deps[(string) $package['name']] = (string) $package['version'];
}
return $deps;
}
}
?>

View file

@ -0,0 +1,174 @@
<?php
/**
* File containing the ezcBaseOptions class.
*
* @package Base
* @version //autogentag//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Base options class for all eZ components.
*
* @package Base
* @version //autogentag//
*/
abstract class ezcBaseOptions implements ArrayAccess
{
/**
* Container to hold the properties
*
* @var array(string=>mixed)
*/
protected $properties;
/**
* Construct a new options object.
* Options are constructed from an option array by default. The constructor
* automatically passes the given options to the __set() method to set them
* in the class.
*
* @throws ezcBasePropertyNotFoundException
* If trying to access a non existent property.
* @throws ezcBaseValueException
* If the value for a property is out of range.
* @param array(string=>mixed) $options The initial options to set.
*/
public function __construct( array $options = array() )
{
foreach ( $options as $option => $value )
{
$this->__set( $option, $value );
}
}
/**
* Merge an array into the actual options object.
* This method merges an array of new options into the actual options object.
*
* @throws ezcBasePropertyNotFoundException
* If trying to access a non existent property.
* @throws ezcBaseValueException
* If the value for a property is out of range.
* @param array(string=>mixed) $newOptions The new options.
*/
public function merge( array $newOptions )
{
foreach ( $newOptions as $key => $value )
{
$this->__set( $key, $value );
}
}
/**
* Property get access.
* Simply returns a given option.
*
* @throws ezcBasePropertyNotFoundException
* If a the value for the property options is not an instance of
* @param string $propertyName The name of the option to get.
* @return mixed The option value.
* @ignore
*
* @throws ezcBasePropertyNotFoundException
* if the given property does not exist.
* @throws ezcBasePropertyPermissionException
* if the property to be set is a write-only property.
*/
public function __get( $propertyName )
{
if ( $this->__isset( $propertyName ) === true )
{
return $this->properties[$propertyName];
}
throw new ezcBasePropertyNotFoundException( $propertyName );
}
/**
* Sets an option.
* This method is called when an option is set.
*
* @param string $propertyName The name of the option to set.
* @param mixed $propertyValue The option value.
* @ignore
*
* @throws ezcBasePropertyNotFoundException
* if the given property does not exist.
* @throws ezcBaseValueException
* if the value to be assigned to a property is invalid.
* @throws ezcBasePropertyPermissionException
* if the property to be set is a read-only property.
*/
abstract public function __set( $propertyName, $propertyValue );
/**
* Returns if a option exists.
*
* @param string $propertyName Option name to check for.
* @return bool Whether the option exists.
* @ignore
*/
public function __isset( $propertyName )
{
return array_key_exists( $propertyName, $this->properties );
}
/**
* Returns if an option exists.
* Allows isset() using ArrayAccess.
*
* @param string $propertyName The name of the option to get.
* @return bool Whether the option exists.
*/
public function offsetExists( $propertyName )
{
return $this->__isset( $propertyName );
}
/**
* Returns an option value.
* Get an option value by ArrayAccess.
*
* @throws ezcBasePropertyNotFoundException
* If $propertyName is not a key in the $properties array.
* @param string $propertyName The name of the option to get.
* @return mixed The option value.
*/
public function offsetGet( $propertyName )
{
return $this->__get( $propertyName );
}
/**
* Set an option.
* Sets an option using ArrayAccess.
*
* @throws ezcBasePropertyNotFoundException
* If $propertyName is not a key in the $properties array.
* @throws ezcBaseValueException
* If the value for a property is out of range.
* @param string $propertyName The name of the option to set.
* @param mixed $propertyValue The value for the option.
*/
public function offsetSet( $propertyName, $propertyValue )
{
$this->__set( $propertyName, $propertyValue );
}
/**
* Unset an option.
* Unsets an option using ArrayAccess.
*
* @throws ezcBasePropertyNotFoundException
* If $propertyName is not a key in the $properties array.
* @throws ezcBaseValueException
* If a the value for a property is out of range.
* @param string $propertyName The name of the option to unset.
*/
public function offsetUnset( $propertyName )
{
$this->__set( $propertyName, null );
}
}
?>

View file

@ -0,0 +1,75 @@
<?php
/**
* File containing the ezcBaseAutoloadOptions class
*
* @package Base
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Class containing the basic options for ezcBase' autoload.
*
* @property bool $preload
* If component preloading is enabled then as soon as one of the
* classes of a component is request, all other classes in the
* component are loaded as well (except for Exception classes).
* @property bool $debug
* If debug is enabled then the autoload method will show exceptions
* when a class can not be found. Because exceptions are ignored by
* PHP in the autoload handler, you have to catch them in autoload()
* yourself and do something with the exception message.
*
* @package Base
* @version //autogen//
*/
class ezcBaseAutoloadOptions extends ezcBaseOptions
{
/**
* Constructs an object with the specified values.
*
* @throws ezcBasePropertyNotFoundException
* if $options contains a property not defined
* @throws ezcBaseValueException
* if $options contains a property with a value not allowed
* @param array(string=>mixed) $options
*/
public function __construct( array $options = array() )
{
$this->preload = false;
$this->debug = false;
parent::__construct( $options );
}
/**
* Sets the option $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property $name is not defined
* @throws ezcBaseValueException
* if $value is not correct for the property $name
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'debug':
case 'preload':
if ( !is_bool( $value ) )
{
throw new ezcBaseValueException( $name, $value, 'bool' );
}
$this->properties[$name] = $value;
break;
default:
throw new ezcBasePropertyNotFoundException( $name );
}
}
}
?>

View file

@ -0,0 +1,42 @@
<?php
/**
* File containing the ezcBaseStruct.
*
* @package Base
* @version //autogentag//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Base class for all struct classes.
*
* @package Base
* @version //autogentag//
*/
class ezcBaseStruct
{
/**
* Throws a BasePropertyNotFound exception.
*
* @param string $name
* @param mixed $value
* @ignore
*/
final public function __set( $name, $value )
{
throw new ezcBasePropertyNotFoundException( $name );
}
/**
* Throws a BasePropertyNotFound exception.
*
* @param string $name
* @ignore
*/
final public function __get( $name )
{
throw new ezcBasePropertyNotFoundException( $name );
}
}
?>

View file

@ -0,0 +1,72 @@
<?php
/**
* File containing the ezcBaseFileFindContext class.
*
* @package Base
* @version //autogentag//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Struct which defines the information collected by the file walker for locating files.
*
* @package Base
* @version //autogentag//
*/
class ezcBaseFileFindContext extends ezcBaseStruct
{
/**
* The list of files
*
* @var array(string)
*/
public $elements;
/**
* The number of files
*
* @var int
*/
public $count;
/**
* The total file size of all files found
*
* @var int
*/
public $size;
/**
* Constructs a new ezcBaseFileFindContext with initial values.
*
* @param array(string) $elements
* @param int $count
* @param int $size
*/
public function __construct( $elements = array(), $count = 0, $size = 0 )
{
$this->elements = $elements;
$this->count = $count;
$this->size = $size;
}
/**
* Returns a new instance of this class with the data specified by $array.
*
* $array contains all the data members of this class in the form:
* array('member_name'=>value).
*
* __set_state makes this class exportable with var_export.
* var_export() generates code, that calls this method when it
* is parsed with PHP.
*
* @param array(string=>mixed) $array
* @return ezcBaseFileFindContext
*/
static public function __set_state( array $array )
{
return new ezcBaseFileFindContext( $array['elements'], $array['count'], $array['size'] );
}
}
?>

View file

@ -0,0 +1,83 @@
<?php
/**
* File containing the ezcBaseRepositoryDirectory.
*
* @package Base
* @version //autogentag//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Struct which defines a repository directory.
*
* @package Base
* @version //autogentag//
*/
class ezcBaseRepositoryDirectory extends ezcBaseStruct
{
/**
* Specifies that the entry is for the eZ Components repository.
*/
const TYPE_INTERNAL = 0;
/**
* Specifies that the entry is for an external (user defined) repository.
*/
const TYPE_EXTERNAL = 1;
/**
* The $type is one of the two TYPE_* constants defined in this class.
*
* @var string
*/
public $type;
/**
* The path to the configured repository.
*
* @var string
*/
public $basePath;
/**
* The path to the autoload files.
*
* @var string
*/
public $autoloadPath;
/**
* Constructs a new ezcBaseRepositoryDirectory of type $type with base path
* $basePath and autoload path $autoloadPath.
*
* @param string $type
* @param string $basePath
* @param string $autoloadPath
*/
public function __construct( $type, $basePath, $autoloadPath )
{
$this->type = $type;
$this->basePath = $basePath;
$this->autoloadPath = $autoloadPath;
}
/**
* Returns a new instance of this class with the data specified by $array.
*
* $array contains all the data members of this class in the form:
* array('member_name'=>value).
*
* __set_state makes this class exportable with var_export.
* var_export() generates code, that calls this method when it
* is parsed with PHP.
*
* @param array(string=>mixed) $array
* @return ezcBaseRepositoryDirectory
*/
static public function __set_state( array $array )
{
return new ezcBaseRepositoryDirectory( $array['type'], $array['basePath'], $array['autoloadPath'] );
}
}
?>

View file

@ -0,0 +1,32 @@
CREDITS
=======
eZ Components team
------------------
- Sergey Alexeev
- Sebastian Bergmann
- Jan Borsodi
- Raymond Bosman
- Frederik Holljen
- Kore Nordmann
- Derick Rethans
- Vadym Savchuk
- Tobias Schlitt
- Alexandru Stanoi
Contributors
------------
- Sinisa Dukaric
* searchMailbox addition for IMAP transport
- Mikko Koppanen
* various IMAP transport enhancements
* SSL support for IMAP and POP3
- Christian Michel
* SSL/TLS support for SMTP transport

View file

@ -0,0 +1,546 @@
1.7beta1 - Monday 23 November 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #15837: imap.google.com (google gmail) changed IMAP response.
1.7alpha1 - Monday 09 November 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed test cases for PHP 5.3 and later.
- Implemented feature request #14023: Split ezcMailComposer's addAttachment
into a function for adding file attachments and for adding attachments from
strings.
- Implemented feature request #14257: Problem accessing multiple headers with
same headername.
- Implemented feature request #14487: Enable ezcMailComposer to specify
encoding for text and html parts.
- Implemented feature request #14794: Add an option to parse text attachments
as file part instead of text part.
- Fixed issue #15341: ezcMailFileParser class function appendStreamFilters not
working properly for quoted-printable.
- Fixed issue #15456: Problems with parsing emails that have "charset = "
instead of "charset=".
1.6.3 - Monday 22 June 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #15068: false ezcMail tests. Based on a patch from Thomas Koch.
1.6.2 - Monday 11 May 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #14776: ezcMailStorageSet generates bad file names.
1.6.1 - Monday 09 February 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #14242: Cannot append email through IMAP.
- Fixed issue #14360: problems with $imap->top() command in gmail.
1.6 - Monday 05 January 2009
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #14220: File attachments mess up emails without body text.
1.6rc1 - Monday 15 December 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #14025: Problem with ezcMailComposer::addAttachment when use the
fifth param to change the file name.
1.6beta1 - Monday 01 December 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #14009: ezcMailTools::validateEmailAddressMx() uses wrong HELO
domain name.
- The function ezcMailTools::validateEmailAddressMx() throws an exception if
there is no support for getmxrr() and checkdnsrr().
- Altered the ezcMailTools::validateEmailAddress() regexp to protect against
locale issues.
1.6alpha1 - Monday 10 November 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Implemented issue #13383: Add a method to extract/change/replace entities in
HTML mail with the CID elements replaced.
- Implemented feature request #13539: Add new mail parser option fileClass.
- Fixed issue #13878: Endless loop in ezcMailParser.
1.5.2 - Monday 06 October 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an issue that caused the part boundaries from e-mail messages not
being correctly set in the parsed mail structure. Instead an auto-generated
one was used.
- Fixed issue #13553: Documented how to access the raw value of headers.
- Implemented feature request #13538: Added possibility to set a custom
message in mail multiparts for e-mail clients missing MIME support.
1.5.1 - Monday 04 August 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #13329: ezcMail fetchParts() no longer generates an error when
parsing a mail with an empty body.
- Fixed a special case in sortFromOffset() where $range was undefined.
- Fixed an issue with duplicate properties arrays in mail part descendants.
1.5 - Monday 16 June 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- No changes.
1.5rc1 - Tuesday 10 June 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #13038: Added support for non-ascii and mime-emcoded (non-RFC)
filenames for mail attachments.
1.5beta1 - Tuesday 27 May 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #13010: The transport connection handles correcly cases where
CRLF is split in 2 different blocks read from server.
1.5alpha1 - Monday 05 May 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #12844: getTmpDir() not properly set in Windows.
- Fixed issue #12903: The mail digest size is not calculated twice anymore.
- Fixed issue #12930: The SMTP authentication methods are used in correct
strength order now.
- Implemented feature request #11937: Switch to turn off automatic inclusion
of files with the Mail Composer.
- Implemented feature request #12203: Replaced hard-coded paths for temporary
directory with the PHP 5.2.1 function sys_get_temp_dir().
- Implemented feature request #12694: Replace reflection test for class type
with SPL function.
1.4.3 - Monday 03 March 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #12595: Folding is no longer applied twice for To, Cc and Bcc
headers.
1.4.2 - Thursday 17 January 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #12372: MTA transport does not encode subject.
1.4.1 - Monday 14 January 2008
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #12318: Unsafe characters are replaces by underscores in
attachment file names during mail parsing.
1.4 - Monday 17 December 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- No changes
1.4rc1 - Wednesday 05 December 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #12138: Mail's IMAP transport can hang when connection gets
dropped.
1.4beta1 - Wednesday 28 November 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #11906: Only files inside an image tag are attached to the
composed email.
- Fixed issue #11965: Reading from a transport connection is stopped at CRLF
or a problem in the connection, and not after a hard-coded number of loops.
- Fixed issue #12062: Mails with no space or tabs after the colon in headers
are parsed correctly now.
1.4alpha2 - Monday 29 October 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #11582: ezcMailImapSet won't be caught in an infinite loop if
the mail headers or body contain an IMAP tag.
- The IMAP, POP3 and SMTP transports and the ezcMailParser class can receive
options objects in the constructor. They can still receive options as arrays
to keep compatibility.
1.4alpha1 - Tuesday 18 September 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Implemented feature request #8436: Added the method validateEmailAddress()
in ezcMailTools.
- Implemented feature request #10459: Added the searchMailbox() method to the
IMAP transport. Based on a patch from Sinisa Dukaric.
- Implemented feature request #10659: Added the getHierarchyDelimiter() method
to the IMAP transport.
- Implemented feature request #10996: Added support for the SMTP authentication
methods DIGEST-MD5, CRAM-MD5, NTLM and LOGIN.
- Implemented feature request #10999: Added the possibility to refer to
messages by their unique IDs in IMAP.
- Implemented feature request #11061: Added missing conditions for SMTP
methods.
- Implemented feature request #11299: Added an optional argument to the
setHeader() method in ezcMailPart to assign a charset to a header.
- Added the fetchSizes() method in IMAP which returns the sizes of the
specified messages.
1.3.1 - Monday 30 July 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #11175: ezcMailTools::composeEmailAddress quotes the name part
if it contains special characters ( , @ < > : ; ' " ).
- Fixed issue #11174: ezcMailHeaderFolder::foldAny doesn't add a line break in
front of the header value if it is exactly 76 characters.
1.3 - Monday 02 July 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- No changes.
1.3rc1 - Monday 25 June 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Documentation updates and fixes.
1.3beta2 - Thursday 31 May 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed issue #10762: Mail file set does not work with php://stdin.
1.3beta1 - Monday 07 May 2007
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added walkParts() to ezcMail and the class ezcMailPartWalkContext which can
be used to walk through all the parts in a mail and execute a callback
function on each part (for example save mail parts to disk or a database).
- Added support for multipart/report and message/delivery-status mail parts,
connected to issue #8694.
- Added header folding for the Content-Disposition header.
- Fixed an issue with ezcMailHeaderFolder::foldAny() where notices were thrown
if the header contained a too long string without any white spaces.
- Fixed issue #10656: Parsing of incomplete multipart/related mails does not
trigger a notice anymore.
- Fixed ezcMailTransportException to inherit from ezcMailException, and not
directly from ezcBaseException.
- Implemented feature #8303: Added fetchParts() to ezcMail to return the mail
parts of a mail.
- Implemented feature #8419: added the property size to ezcMailPart,
which is set when parsing a mail.
- Implemented feature #8485: added the ezcMailStorageSet which wraps
around another set and provides saving of mail sources.
- Implemented feature #9068: added support for filename language and
filename charset support for the Content-Disposition header.
- Implemented feature #9292: added SSL support for IMAP and POP3.
Based on a patch from Mikko Koppanen.
- Implemented feature #9308: added option classes for transports.
- Implemented feature #9785: Allow developers to specify their own
character conversion function to UTF-8. Also fixed issue #8369 as developers
can ignore the notices thrown by iconv in their own conversion function.
- Implemented feature #10068: added a list of supported RFCs to the
documentation.
- Implemented feature #10082: added options class ezcMailParserOptions
and deprecated second parameter of parseMail() in ezcMailParser.
- Implemented feature #10091: added SSL/TLS support for the SMTP
transport. Based on a patch from Christian Michel.
- Implemented feature #10340: More selective encoding of mail headers.
- Implemented feature #10341: MixedPart mail without attachments -
Documentation enhancement
- Implemented feature #10682: The IMAP PEEK command is now supported
through the top() method. Added PEEK support to sortMessages() also.
- Fixed a problem with certain IMAP servers which didn't allow the second
parameter of top() method from IMAP to be 0.
1.2.1 - [RELEASEDATE]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added ezcMailTools::guessContentType to resolve a bug in which the images
embeded in an html part were treated like application/octet-stream
attachments.
- Fixed bug #010138: Doc of ezcMailMultipartDigest->__construct() incorrect
(The documentation was correct, the implementation was wrong.)
- Fixed issue #10283: ImapSet does not return the trailing parenthesis ')'.
- Fixed issue #10312: Fixed the value of ezcMail::QUOTED_PRINTABLE constant.
- Fixed issue #10200 (part 1): Content-Disposition header is no longer created
during parsing if it is missing.
- Fixed issue #10200 (part 2): The value of the generated Content-ID header
contains the filename encoded with base64 to avoid problems.
- Fixed issue #10136: ezcMailImapSet, ezcMailPop3Set and ezcMailMboxSet not
marked as private anymore.
- Fixed issue #10358: correct call to the ezcMailTextParser constructor in
case the parsed message contains an unrecognized MIME main type.
- Fixed issue #10389: tab characters are converted to one space when parsing
mails with wrapped headers.
- Fixed issue #10359: unrecognized mail body parts are parsed using the
ezcMailFileParser.
- Fixed issue #10396: Method convertToUTF8 assumes 'latin1' charset instead of
'unknown-8bit' and 'x-user-defined'.
1.2 - Monday 18 December 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- No changes.
1.2beta2 - Monday 20 November 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added feature #9079: The ability to add mail attachments using streams.
- Added feature #9100: The ability to set the character set in the
composer for text and HTML parts.
- Added feature #9331: Added the returnPath property in ezcMail to set the
envelope address while sending mail with the SMTP and MTA transports.
- Added feature #9334: Added the getMessageNumbers() method to the IMAP and
POP3 sets to return message numbers. Patch by Mikko Koppanen.
- Fixed an issue in ezcMailPart: When setting the headers property the wrong
exception was thrown.
- Fixed bug #9042: added __isset() method to classes that use properties.
- Fixed bug #9442: added missing hasData() method to ezcMailVariableSet.
- Various additions to the IMAP Transport:
* Added features #9171, #9172, #9206, #9228: Added the fetchByFlag(),
countByFlag(), setFlag(), clearFlag() methods. Patches by Mikko Koppanen.
* Added feature #9173: Changed the status() method to also return the number
of recent and unseen messages.
* Added features #9212 and #9228: Added the createMailbox(), renameMailbox(),
deleteMailbox() and copyMessages() methods. Patches by Mikko Koppanen.
* Added feature #9229: Added a parameter to selectMailbox to select a mail
box in readonly mode. Patch by Mikko Koppanen.
* Added feature #9333: Added the sortMessages(), sortFromOffset() and
fetchFlags() methods. Patches by Mikko Koppanen.
* Added feature #9336: Added the expunge() method. Patch by Mikko Koppanen.
* Added feature #9423: Added the capability() method. Patch by Mikko
Koppanen.
* Added feature #9424: Added the noop() method in IMAP and POP3 transports.
Patch by Mikko Koppanen.
* Added feature #9425: Added the append() method.
1.2beta1 - Tuesday 24 October 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added IMAP transport.
- Added fetchFromOffset() method to POP3 and MBOX transports.
- Implemented suggestion #8988: ezcMailAddress should implement __toString().
- Implemented suggestion #8989: Extending the ezcMail class.
ezcMailParser->parse() can now deal with classes that extend ezcMail.
Additionally, added this functionality to ezcMailTool::replyToMail().
- Implemented read access to property ezcMailPart->headers for extending this
class and its derives.
- Added a new class (ezcMailVirtualFile) to allow attachments from memory.
- Added an optional parameter to listMessages() method in IMAP, to return
messages with a certain Content-Type header.
1.1.3 - Monday 09 October 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed bug #8990: ezcMail->messageID should be named ezcMail->messageId.
- Fixed bug #9048: ezcMailText does not encode properly.
- Fixed bug #9049: Long headers are not wrapped and could cause MTA warnings.
- Fixed bug #8850: Support multiline header parameters by
implementing RFC2231.
- Fixed a bug in ezcMailPart: The getHeader() function returns an empty
string instead of null in case of an unknown header.
- Fixed a bug in ezcMailRfc822Parser: The bcc is set correctly now while
parsing e-mail.
- Fixed a bug in ezcMailMultipartRelated: The getRelatedParts() and
getRelatedPartByID() functions return now correct values if the main part of
the message is missing.
- Fixed a bug in ezcMailMtaTransport and ezcMailSmtpTransport: Checking for
sending a message without recipients.
- Fixed a bug in ezcMailImapTransport: listUniqueIdentifiers() does not hang
anymore when the supplied parameter is an invalid message number.
- Implemented support for character set and language for
ezcContentDispositionHeader.
- Fixed an issue with mbox files without an mbox header being present.
1.1.2 - Monday 28 August 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the ezcMailPop3Transport::fetchByMessageNr() method that returns an
ezcMailPop3Set containing the message with the specified number.
- Fixed bug #8736: variable transport non-functional.
- Fixed bug that caused the contentId property of the ezcMailFile class not to
be set even if it was available for the related part while parsing
multipart/related messages.
- PHP 5.2 compatibility.
1.1.1 - Monday 07 August 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Partially fixed bug #8694:
* Don't crash when generating empty mail.
* Don't assume that message/ parts are actually rfc822 messages when parsing
mail.
1.1 - Monday 12 June 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed CS issues and tests.
1.1rc1 - Monday 29 May 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the ezcMailTools::replyToMail() method that will create a reply
message with the correct headers set (from, to, cc, ,subject, references and
in-reply-to) based on an existing mail message.
- Added workaround for bug #8271: Mail parsing bug in email with PGP signature.
We don't support GPG at the moment, however we now recognize it and ignore keys
and signatures.
- Added the ezcMailSmtpTransport::keepConnection() method. This allows keeping
the connection open when sending several mails.
- Added the ezcMail::messageID property which represents the ID of a mail
message.
- Added the ezcMail::timestamp property which is generated from the Date
header.
- Added the ezcMailMboxTransport and changed ezcMailMboxSet to work together
with that one.
- Added $encoding parameter to ezcMailTools::parseMailAddress and
ezcMailTools::parseMailAddresses. This allows you to parse not only
RFC822 compliant address strings but also address strings in local
encoding. This is useful when ezcMailAddress items directly from
user inserted address string (e.g from a composer window).
- Added feature #8266: Property for the Content-Disposition
stuff on the ezcMailPart level. Implemented for both parsing and sending.
- Changed mime string decoding to be more robust by trying to work around
common mistakes by MUAs.
- Changed the way how character sets are handled. From now on all text parts
will automatically be converted to UTF-8. The original character set
belonging to the e-mail is stored in the originalCharset property, while the
charset property will now always return "UTF-8" for text parts.
- Changed header storage so that headers are now stored case sensitive but
retrieved case insensitive. This is useful since headers are case
insensitive, but do have a preferred case. When fetching headers it is handy
not to have to try all possible permutations.
- Fixed a bug where parsing would fail because there was no trailing ';' in
the Content-Type field.
- Fixed an issue where mime decoding of headers failed because of a bug in
PHP.
1.1beta2 - Tuesday 09 May 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the getRelatedPartByID() method to ezcMailMultipartRelated that
returns a mail part by looking for it's Content-ID.
- Added the class ezcMailFileSet that can be used to parse mail messages
in a file directly from disk.
- Added the class ezcMailVariableSet that can be used to parse mail messages
directly from a variable.
- Changed the POP3 classes to leave the mail on the server by default. You
need to actively set $deleteFromServer in order to have it removed.
1.1beta1 - Wednesday 19 April 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added the mbox transport for reading mbox files to use with the
ezcMailParser.
- Fixed a bug that caused filenames with spaces to appear mangled.
- Fixed a bug where the encodings 7bit and 8bit were not handled correctly.
- Fixed a bug where text attachments missed line breaks when saved to disk.
1.1alpha1 - Monday 03 April 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added functionality for parsing mail messages. The main class is
ezcMailParser.
- Added the POP 3 mail retrieving transport for use with the ezcMailParser.
- Added method ezcMailPart::setHeaders to set multiple headers at once.
- Added method ezcMailTools::parseEmailAddress and parseEmailAddresses that
parse RFC 2822 email addresses.
- Added class ezcMailRfc822Digest inheriting ezcMailPart. This part can be
used to create mail digest messages.
- Added class ezcMailMultipartDigest which represents multipart/digest parts.
- Renamed ezcMailTransportMta and ezcMailTransportSmtp to ezcMailMtaTransport
and ezcMailSmtpTransport. The old classes still exist but are deprecated.
1.0.1 - Monday 20 February 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed bug #7805: Removed double linebreak in ezcMailTransportMta::send().
- Fixed bug #7813: MultipartRelated with non-file parts may throw exception
if you did not set a Content-ID.
- Implemented suggesion #7804:
* Added getParts() to ezcMailMultipart.
* Added getParts() to ezcMailMultipartMixed and MultipartAlternative.
* Added getMainPart() and getRelatedParts to ezcMultipartRelated.
1.0 - Monday 30 January 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Changed ezcMailException to inherit from ezcBaseException instead of
Exception.
- Fixed bug #7716: ezcMail needs support for Reply-To. We simply don't set it
anymore now. Users can set the header themselves if they need to.
(ezcMailPart::setHeader())
- Fixed issue with double To and Subject headers when using the MTA transport.
1.0rc1 - Monday 16 January 2006
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Added feature enhancement #7582: Adding multiple parts as an array.
- Changed ezcMailText::characterSet property to charset.
- Changed ezcMailSmtpTransport and made all protected methods private. They
exposed an interface that most likely never will have to be changed.
- Changed exception behavior. All errors will now throw a different exception
class.
- Fixed bug #7637: "ezcMailComposer doesn't encode headers".
1.0beta2 - Wednesday 21 December 2005
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Completely revised documentation.
- Replaced the mail_address array with the ezcMailAddress 'struct'.
- Renamed ezcMailTextPart to ezcMailText
- Renamed ezcMailFilePart to ezcMailFile
- Fixed problem with sending mail with cc and bcc recipients.
- Fixed bug #7576: RFC 2606 compliance
- Fixed bug #7577: unable to run example_general.php
- Fixed bug #7578: mail example errors
1.0beta1 - Thursday 24 November 2005
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Initial release of this package.

View file

@ -0,0 +1,4 @@
The component allows you construct and/or parse Mail messages conforming to
the mail standard. It has support for attachments, multipart messages and HTML
mail. It also interfaces with SMTP to send mail or IMAP, POP3 or mbox to
retrieve e-mail.

View file

@ -0,0 +1,53 @@
{
"authors": [
{
"name": "Sergey Alexeev"
},
{
"name": "Sebastian Bergmann"
},
{
"name": "Jan Borsodi"
},
{
"name": "Raymond Bosman"
},
{
"name": "Frederik Holljen"
},
{
"name": "Kore Nordmann"
},
{
"name": "Derick Rethans"
},
{
"name": "Vadym Savchuk"
},
{
"name": "Tobias Schlitt"
},
{
"name": "Alexandru Stanoi"
},
{
"name": "Sinisa Dukaric"
},
{
"name": "Mikko Koppanen"
},
{
"name": "Christian Michel"
}
],
"autoload": {
"classmap": [
"src"
]
},
"description": "The component allows you construct and/or parse Mail messages conforming to the mail standard. It has support for attachments, multipart messages and HTML mail. It also interfaces with SMTP to send mail or IMAP, POP3 or mbox to retrieve e-mail.",
"homepage": "https://github.com/zetacomponents",
"license": "apache2",
"name": "zetacomponents/mail",
"type": "library"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View file

@ -0,0 +1,121 @@
eZ publish Enterprise Component: Mail, Design
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Introduction
============
Purpose of Mail package
-----------------------
The purpose of the Mail package is to create and send mail. It must
support the at least the most common mail functions.
Current implementation
----------------------
Currrently Mail functionality is implemented in the class
eZMail and the transportclasses eZSMTPTransport and eZSsendmailTransport.
Requirements
=============
It must support sending mail using
- the default PHP MTA.
- SMTP
The composer must support the following
- Plain text mail sending
- HTML mail sending (with images)
- Alternative mails (text and HTML parts)
- Attachments (images/video and other binary data)
The implementation must conform to the following specifications:
Mime
http://www.faqs.org/rfcs/rfc2045.html
http://www.faqs.org/rfcs/rfc2046.html
http://www.faqs.org/rfcs/rfc2047.html
http://www.faqs.org/rfcs/rfc2048.html
http://www.faqs.org/rfcs/rfc2049.html
Mime multipart
http://www.faqs.org/rfcs/rfc2387.html
Mime encapsulation (HTML mail)
http://www.faqs.org/rfcs/rfc2557.html
Content-Disposition field
http://www.faqs.org/rfcs/rfc2183.html
Mail
http://www.faqs.org/rfcs/rfc822.html
http://www.faqs.org/rfcs/rfc2822.html
It must be possible to later extend the model so it can also parse
and read mail.
Design
======
The design is split into two parts.
1. The design of the mail itself
2. The design of the mail transport
Mail Class design
----------------------
The design of the mail itself is built around the MIME
specifications. This is to allow easy parsing of mail later. It also
allows the building of advanced MIME mail structures if needed.
ezcMailPart
ezcMailPart is an abstract base class for all mail structures. It
holds one MIME part and is responsible for storing the headers for
a MIME part. The generate method uses the generateHeaders and
generateBody methods to build up the entire (sub) message.
ezcMultipart
Base class for all multipart MIME types.
ezcMailMultipartMixed
Handles multiparts of the type mixed. This is the most common
multipart which is used e.g for attachments.
ezcMailMultipartAlternative
Handles multiparts of the type alternative. This is used for HTML
messages where you also want to support plain text mail clients.
ezcMailMultipartRelated
Handles multiparts of the type related. This is used to connect
related parts to a main part e.g images in an HTML message.
ezcMailTextPart
Handles text parts of a message. This class is not only used for
plain text but also for e.g HTML messages.
ezcMailFilePart
Handles all file attachments.
ezcMail
Base class for mail creation. This base class contains the basic
functionality needed to build e-mail.
ezcMailComposer
Convinience class that can be used to create the most common e-mail
messages. This class handles the creation of the internal parts
internally.
Transport Class design
----------------------
ezcMailTransport
Abstract interface for sending e-mail.
ezcMailTransportMta
Implementation of the mail transport interface using the mail
function found in PHP.
ezcMailTransportSmtp
Implementation of mail transport interface using SMTP to send mail.

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -0,0 +1,64 @@
[X] Options should always be done through an options class, and no longer
through arrays like is shown in trunk/Mail/docs/tutorial/tutorial_smtp_auth.php.
See: http://ez.no/ezcomponents/contributing/coding_standards#id45
As in this case there are options before, the functionality should stay,
but the array() way of passing objects should not be documented.
- The IMAP, POP3 and SMTP transports and the ezcMailParser class can receive
options objects in the constructor. They can still receive options as arrays
to keep compatibility.
- TS: Actually we should not even document anymore, that an array also
works as options. Just the option class itself should be documented so
no new users start with the deprecated way of handling options. The
default value for $options in ctors should also be null, not array()
then.
[X] The same in ezcMailImapSet but as that did not have options before, the
array way should not be supported at all.
- To keep consistency in the whole package array options were used.
[X] The "James Bond" header looks broken to me in the tutorial.
- Fixed.
[ ] Shouldn't the charset for headers default to "Utf-8" instead of "us-ascii"?
I am not sure what we do in other cases, it of course has to be consistent.
- TS: I think we should default to UTF-8 everywhere we need to define a
default charset.
[ ] Isn't the "$charset = $this->getHeaderCharset" to
"$value = substr( $value, 7 ); // "dummy: " + 1" bit copied from somewhere?
If so, we should make this a new (private) method somewhere.
[X] In ezcMailImapTransport, why did you change many properties to protected
(from private)?
- I think it makes more sense to have protected properties, and also makes
it easier to test.
[X] I see some strange things with ezcMailTransportMta vs ezcMailMtaTransport
in the trunk/Mail/src/transports/mta/mta_transport.php file... are you
sure you didn't swap something? Or was it fucked up before? :)
- ezcMailTransportMta is a wrong name so it is deprecated in transport_mta.php
ezcMailMtaTransport is correct and it is in mta_transport.php
[X] The same thing seems to be going on with ezcMailTransportSmtp vs
ezcMailSmtpTransport.
- The same thing above.
[ ] In ezcMailTools::validateEmailAddressMx() we are using smtp.ez.no in the
HELO command. This will be incorrect for most of the use cases, since HELO
should identify the server that is opening the communication. We should
either rely on $_SERVER['SERVER_NAME'] or let the user supply the domain
to use in HELO. Same applies for the sender email address. This should
either be "postmaster@{$_SERVER['SERVER_NAME']}" or also configurable.
[ ] On my system several failures and warnings occur. I guess this is mostly
because test cases don't get skipped that are only working inside the eZ
network, but some seem to have real problems. For details, please check
http://home.schlitt.info:8080/buildresults/Mail.

View file

@ -0,0 +1,91 @@
ezcMailComposerOptions
======================
- Cast to bool is not necessary in Mail/src/options/composer_options.php +75.
# Done.
SMTP Auth methods
=================
- Why is there only a failure case tested? I don't see (at a first glance)
that the sorting is really tested at all. If I'm wrong with that: Please add
a comment to the test. Thanks!
# I added a comment to the test.
Testing
=======
- 1 failure with 5.2.6 on ezctest: ::
1) testValidateEmailAddressIncorrect(ezcMailToolsTest)
Failed asserting that µ@example.com is incorrect.
Failed asserting that <boolean:true> matches expected value <boolean:false>.
/home/ts/dev/ezc/trunk/Mail/tests/tools_test.php:273
- Some failures and nasty output on my local maschine (maybe these tests can be
conditionally skipped?): ::
# I don't know anything about this behaviour in MTA. What system do you have on
your PC? Do you have sendmail? The MTA transport uses the mail() function which
is not easy to control and which can output text to the console. Not much to do
here unless somebody knows something. (Note: is hartes-php.de functional?
I cannot connect to it with telnet)
# About the ezcMailToolsTest failure: there was a bug in the getmxrr() PHP
function and I think the failure is caused by that. But we could not find which
bug was it and in which version it was fixed. With what version of PHP did you test?
ezcUnitTest uses the PHPUnit @package_version@ framework from Sebastian Bergmann.
[Preparing tests]:
eZ Components:
Mail:
ezcMailTest: ........................
[snip]
ezcMailMultipartDigestTest: ...
ezcMailToolsTest: ................F..........
ezcMailTransportMtaTest: SSL_connect: Success
sendmail: Cannot open hartes-php.de:25
FSSL_connect: Success
sendmail: Cannot open hartes-php.de:25
F..SSL_connect: Success
sendmail: Cannot open hartes-php.de:25
FSSL_connect: Success
sendmail: Cannot open hartes-php.de:25
E
ezcMailTransportSmtpTest: ..................................
[snip]
There was 1 error:
1) testEncodedHeaders(ezcMailTransportMtaTest)
ezcMailTransportException: An error occured while sending or receiving mail. The email could not be sent by sendmail
/home/dotxp/dev/PHP/actual/ezcomponents/trunk/Mail/tests/transports/transport_mta_test.php:117
--
There were 4 failures:
1) testValidateEmailAddressCorrectMX(ezcMailToolsTest)
Failed asserting that nospam@ez.no is correct with MX.
Failed asserting that <boolean:false> matches expected value <boolean:true>.
/home/dotxp/dev/PHP/actual/ezcomponents/trunk/Mail/tests/tools_test.php:260
2) testFullMail(ezcMailTransportMtaTest)
An error occured while sending or receiving mail. The email could not be sent by sendmail
/home/dotxp/dev/PHP/actual/ezcomponents/trunk/Mail/tests/transports/transport_mta_test.php:44
3) testFullMailMultiple(ezcMailTransportMtaTest)
An error occured while sending or receiving mail. The email could not be sent by sendmail
/home/dotxp/dev/PHP/actual/ezcomponents/trunk/Mail/tests/transports/transport_mta_test.php:58
4) testFullMailReturnPath(ezcMailTransportMtaTest)
An error occured while sending or receiving mail. The email could not be sent by sendmail
/home/dotxp/dev/PHP/actual/ezcomponents/trunk/Mail/tests/transports/transport_mta_test.php:104
FAILURES!
Tests: 602, Failures: 4, Errors: 1, Skipped: 9.

View file

@ -0,0 +1,19 @@
ezcMailPartParser
=================
[x] The function parseHeader() should be refactored. The new code has in
the if() and elseif() case duplicated code that can easily be extracted
into a new private method.
The code is too coupled and the private function will have 4-5 params.
It applies to only 4 lines of code. The solution which I tried actually
looks worse than what it is now.
[x] The test in trunk/Mail/tests/composer_test.php should removed the
added check for "charset=binary" as that is a bug in PHP (line 647ish)
[ ] From reading the code, I don't think that it is possible to use
headers with the same name while creating mail as well. This needs to
be supported so that mails can be forwarded with all current headers
in tact. We'd need to add tests for both generation and forwarding/replying
here.

View file

@ -0,0 +1,58 @@
General:
[WILL NOT FIX]- I prefer to have getXXX() method when the main purpose is to return a value:
ezcMailTools::generateContentID.
[DONE] - Default variables when not set: $aap = '', $aap = null, or $aap = false.
Tests:
[WHAT DO YOU MEAN?]- Set the timezone somewhere that the test run separately.
ezcMail.php:41
[DONE, lacks impl] "Use setSubject if you require a special encoding.": Method setSubject does not exist.
ezcMail::generateHeaders
[DONE] Add doc, only for extension.
composer.php
[DONE, used null] Initialize $this->htmlText and $this->plainText as false in the constructor. Easier to check in other
functions.
tools.php
[IS OK]- uniqueID is not thread safe?
[SINCE IT IS STATIC]- lineBreak -> getLineBreak(). And why not a property?
[NO STRUCT ANYMORE THEN]- Tools work upon the mailAddress struct, but why not implement the methods
there?
mail_address.php
[DONE]- __set_state() not documented ;-).
transport_smtp_exception.php
- The consts are not documented.
file_part.php
- Constructor contains: /*,$encoding = ezcMail::BASE64*/ ..
- Can encoding be removed from the __get(), and __set() ?
[I'm letting it stay in the case we implement it..]
transport_smtp.php
[DONE]- consts are not documented.
[DONE]- You can link to the consts, if you want to.. e.g. in $status.
[DONE]- login(), throws also an Exceptions if the auth fails. Is not documented.
[WILL NOT FIX]- composeSmtpMailAddress .. or getComposedSmtpMailAddress ?
Review Derick
=============
ezcMail.php:
misses a "setFrom", "setSubject", and "setBody" function
[added setSubject because of charset encoding, the others are properties]
[DONE] ezcMail::__get doesn't check whether the properties have all been set (I get
undefined index notices with the new test case that I just added)
[now initialized to null]
Bugs:
[DONE] http://ez.no/bugs/view/7577
http://ez.no/bugs/view/7512
[DONE] http://ez.no/bugs/view/7578
[DONE] http://ez.no/bugs/view/7576
http://ez.no/bugs/view/7582

View file

@ -0,0 +1,537 @@
<?php
/**
* File containing the ezcMailComposer class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Convenience class for writing mail.
*
* This class allows you to create
* text and/or HTML mail with attachments. If you need to create more
* advanced mail use the ezcMail class and build the body from scratch.
*
* ezcMailComposer is used with the following steps:
* 1. Create a composer object.
* 2. Set the subject and recipients.
* 3. Set the plainText and htmlText message parts. You can set only one
* or both. If you set both, the client will display the htmlText if it
* supports HTML. Otherwise the client will display plainText.
* 4. Add any attachments (addFileAttachment() or addStringAttachment()).
* 5. Call the build method.
*
* This example shows how to send an HTML mail with a text fallback and
* attachments. The HTML message has an inline image.
* <code>
* $mail = new ezcMailComposer();
* $mail->from = new ezcMailAddress( 'john@example.com', 'John Doe' );
* $mail->addTo( new ezcMailAddress( 'cindy@example.com', 'Cindy Doe' ) );
* $mail->subject = "Example of an HTML email with attachments";
* $mail->plainText = "Here is the text version of the mail. This is displayed if the client can not understand HTML";
* $mail->htmlText = "<html>Here is the HTML version of your mail with an image: <img src='file://path_to_image.jpg' /></html>";
* $mail->addFileAttachment( 'path_to_attachment.file' );
* $mail->build();
* $transport = new ezcMailMtaTransport();
* $transport->send( $mail );
* </code>
*
* By default, if the htmlText property contains an HTML image tag with file://
* in href, that file will be included in the created message.
*
* Example:
* <code>
* <img src="file:///home/me/image.jpg" />
* </code>
*
* This can be a security risk if a user links to another file, for example logs
* or password files. With the automaticImageInclude option (default value true)
* from {@link ezcMailComposerOptions}, the automatic inclusion of files can be
* turned off.
*
* Example:
* <code>
* $options = new ezcMailComposerOptions();
* $options->automaticImageInclude = false; // default value is true
*
* $mail = new ezcMailComposer( $options );
*
* // ... add To, From, Subject, etc to $mail
* $mail->htmlText = "<html>Here is the image: <img src="file:///etc/passwd" /></html>";
*
* // ... send $mail
* </code>
*
* After running the above code, the sent mail will not contain the file specified
* in the htmlText property.
*
* The file name in the attachment can be different than the file name on disk, by
* passing an {@link ezcMailContentDispositionHeader} object to the function
* addFileAttachment(). Example:
* <code>
* $mail = new ezcMailComposer();
* $mail->from = new ezcMailAddress( 'john@example.com', 'John Doe' );
* $mail->addTo( new ezcMailAddress( 'cindy@example.com', 'Cindy Doe' ) );
* $mail->subject = "Example of an HTML email with attachments and custom attachment file name";
* $mail->plainText = "Here is the text version of the mail. This is displayed if the client can not understand HTML";
* $mail->htmlText = "<html>Here is the HTML version of your mail with an image: <img src='file://path_to_image.jpg' /></html>";
*
* $disposition = new ezcMailContentDispositionHeader();
* $disposition->fileName = 'custom name for attachment.txt';
* $disposition->fileNameCharSet = 'utf-8'; // if using non-ascii characters in the file name
* $disposition->disposition = 'attachment'; // default value is 'inline'
*
* $mail->addFileAttachment( 'path_to_attachment.file', null, null, $disposition );
* $mail->build();
*
* $transport = new ezcMailMtaTransport();
* $transport->send( $mail );
* </code>
*
* Use the function addStringAttachment() if you want to add an attachment which
* is stored in a string variable. A file name for a string attachment needs to
* be specified as well. Example:
*
* <code>
* $contents = 'contents for mail attachment'; // can be a binary string, eg. image file contents
* $mail->addStringAttachment( 'filename', $contents );
* </code>
*
* @property string $plainText
* Contains the message of the mail in plain text.
* @property string $htmlText
* Contains the message of the mail in HTML. You should also provide
* the text of the HTML message in the plainText property. Both will
* be sent and the receiver will see the HTML message if his/her
* client supports HTML. If the HTML message contains links to
* local images and/or files these will be included into the mail
* when generateBody is called. Links to local files must start with
* "file://" in order to be recognized. You can use the option
* automaticImageInclude (default value is true) from
* {@link ezcMailComposerOptions} to turn off the
* automatic inclusion of files in the generated mail.
* @property string $charset
* Contains the character set for both $plainText and $htmlText.
* Default value is 'us-ascii'. This does not set any specific
* charset for the subject, you need the subjectCharset property for
* that.
* @property string $encoding
* Contains the encoding for both $plainText and $htmlText.
* Default value is ezcMail::EIGHT_BIT. Other values are found
* as constants in the class {@link ezcMail}.
* @property ezcMailComposerOptions $options
* Options for composing mail. See {@link ezcMailComposerOptions}.
*
* @package Mail
* @version //autogen//
* @mainclass
*/
class ezcMailComposer extends ezcMail
{
/**
* Holds the attachments filenames.
*
* The array contains relative or absolute paths to the attachments.
*
* @var array(string)
*/
private $attachments = array();
/**
* Holds the options for this class.
*
* @var ezcMailComposerOptions
*/
protected $options;
/**
* Constructs an empty ezcMailComposer object.
*
* @param ezcMailComposerOptions $options
*/
public function __construct( ezcMailComposerOptions $options = null )
{
$this->properties['plainText'] = null;
$this->properties['htmlText'] = null;
$this->properties['charset'] = 'us-ascii';
$this->properties['encoding'] = ezcMail::EIGHT_BIT;
if ( $options === null )
{
$options = new ezcMailComposerOptions();
}
$this->options = $options;
parent::__construct();
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'plainText':
case 'htmlText':
case 'charset':
case 'encoding':
$this->properties[$name] = $value;
break;
case 'options':
if ( !$value instanceof ezcMailComposerOptions )
{
throw new ezcBaseValueException( $name, $value, 'ezcMailComposerOptions' );
}
$this->options = $value;
break;
default:
parent::__set( $name, $value );
}
}
/**
* Returns the property $name.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @return mixed
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'plainText':
case 'htmlText':
case 'charset':
case 'encoding':
return $this->properties[$name];
case 'options':
return $this->options;
default:
return parent::__get( $name );
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'plainText':
case 'htmlText':
case 'charset':
case 'encoding':
return isset( $this->properties[$name] );
case 'options':
return isset( $this->options );
default:
return parent::__isset( $name );
}
}
/**
* Adds the file $fileName to the list of attachments.
*
* If $content is specified, $fileName is not checked if it exists.
* $this->attachments will also contain in this case the $content,
* $contentType and $mimeType.
*
* The $contentType (default = application) and $mimeType (default =
* octet-stream) control the complete mime-type of the attachment.
*
* If $contentDisposition is specified, the attached file will have its
* Content-Disposition header set according to the $contentDisposition
* object and the filename of the attachment in the generated mail will be
* the one from the $contentDisposition object.
*
* @throws ezcBaseFileNotFoundException
* if $fileName does not exists.
* @throws ezcBaseFilePermissionProblem
* if $fileName could not be read.
* @param string $fileName
* @param string $content
* @param string $contentType
* @param string $mimeType
* @param ezcMailContentDispositionHeader $contentDisposition
* @apichange This function might be removed in a future iteration of
* the Mail component. Use addFileAttachment() and
* addStringAttachment() instead.
*/
public function addAttachment( $fileName, $content = null, $contentType = null, $mimeType = null, ezcMailContentDispositionHeader $contentDisposition = null )
{
if ( is_null( $content ) )
{
$this->addFileAttachment( $fileName, $contentType, $mimeType, $contentDisposition );
}
else
{
$this->addStringAttachment( $fileName, $content, $contentType, $mimeType, $contentDisposition );
}
}
/**
* Adds the file $fileName to the list of attachments.
*
* The $contentType (default = application) and $mimeType (default =
* octet-stream) control the complete mime-type of the attachment.
*
* If $contentDisposition is specified, the attached file will have its
* Content-Disposition header set according to the $contentDisposition
* object and the filename of the attachment in the generated mail will be
* the one from the $contentDisposition object.
*
* @throws ezcBaseFileNotFoundException
* if $fileName does not exists.
* @throws ezcBaseFilePermissionProblem
* if $fileName could not be read.
* @param string $fileName
* @param string $contentType
* @param string $mimeType
* @param ezcMailContentDispositionHeader $contentDisposition
*/
public function addFileAttachment( $fileName, $contentType = null, $mimeType = null, ezcMailContentDispositionHeader $contentDisposition = null )
{
if ( is_readable( $fileName ) )
{
$this->attachments[] = array( $fileName, null, $contentType, $mimeType, $contentDisposition );
}
else
{
if ( file_exists( $fileName ) )
{
throw new ezcBaseFilePermissionException( $fileName, ezcBaseFileException::READ );
}
else
{
throw new ezcBaseFileNotFoundException( $fileName );
}
}
}
/**
* Adds the file $fileName to the list of attachments, with contents $content.
*
* The file $fileName is not checked if it exists. An attachment is added
* to the mail, with the name $fileName, and the contents $content.
*
* The $contentType (default = application) and $mimeType (default =
* octet-stream) control the complete mime-type of the attachment.
*
* If $contentDisposition is specified, the attached file will have its
* Content-Disposition header set according to the $contentDisposition
* object and the filename of the attachment in the generated mail will be
* the one from the $contentDisposition object.
*
* @param string $fileName
* @param string $content
* @param string $contentType
* @param string $mimeType
* @param ezcMailContentDispositionHeader $contentDisposition
*/
public function addStringAttachment( $fileName, $content, $contentType = null, $mimeType = null, ezcMailContentDispositionHeader $contentDisposition = null )
{
$this->attachments[] = array( $fileName, $content, $contentType, $mimeType, $contentDisposition );
}
/**
* Builds the complete email message in RFC822 format.
*
* This method must be called before the message is sent.
*
* @throws ezcBaseFileNotFoundException
* if any of the attachment files can not be found.
*/
public function build()
{
$mainPart = false;
// create the text part if there is one
if ( $this->plainText != '' )
{
$mainPart = new ezcMailText( $this->plainText, $this->charset );
}
// create the HTML part if there is one
$htmlPart = false;
if ( $this->htmlText != '' )
{
$htmlPart = $this->generateHtmlPart();
// create a MultiPartAlternative if a text part exists
if ( $mainPart != false )
{
$mainPart = new ezcMailMultipartAlternative( $mainPart, $htmlPart );
}
else
{
$mainPart = $htmlPart;
}
}
// build all attachments
// special case, mail with no text and one attachment.
// A fix for issue #14220 was added by wrapping the attachment in
// an ezcMailMultipartMixed part
if ( $mainPart == false && count( $this->attachments ) == 1 )
{
if ( isset( $this->attachments[0][1] ) )
{
if ( is_resource( $this->attachments[0][1] ) )
{
$mainPart = new ezcMailMultipartMixed( new ezcMailStreamFile( $this->attachments[0][0], $this->attachments[0][1], $this->attachments[0][2], $this->attachments[0][3] ) );
}
else
{
$mainPart = new ezcMailMultipartMixed( new ezcMailVirtualFile( $this->attachments[0][0], $this->attachments[0][1], $this->attachments[0][2], $this->attachments[0][3] ) );
}
}
else
{
$mainPart = new ezcMailMultipartMixed( new ezcMailFile( $this->attachments[0][0], $this->attachments[0][2], $this->attachments[0][3] ) );
}
$mainPart->contentDisposition = $this->attachments[0][4];
}
else if ( count( $this->attachments ) > 0 )
{
$mainPart = ( $mainPart == false )
? new ezcMailMultipartMixed()
: new ezcMailMultipartMixed( $mainPart );
// add the attachments to the mixed part
foreach ( $this->attachments as $attachment )
{
if ( isset( $attachment[1] ) )
{
if ( is_resource( $attachment[1] ) )
{
$part = new ezcMailStreamFile( $attachment[0], $attachment[1], $attachment[2], $attachment[3] );
}
else
{
$part = new ezcMailVirtualFile( $attachment[0], $attachment[1], $attachment[2], $attachment[3] );
}
}
else
{
$part = new ezcMailFile( $attachment[0], $attachment[2], $attachment[3] );
}
$part->contentDisposition = $attachment[4];
$mainPart->appendPart( $part );
}
}
$this->body = $mainPart;
}
/**
* Returns an ezcMailPart based on the HTML provided.
*
* This method adds local files/images to the mail itself using a
* {@link ezcMailMultipartRelated} object.
*
* @throws ezcBaseFileNotFoundException
* if $fileName does not exists.
* @throws ezcBaseFilePermissionProblem
* if $fileName could not be read.
* @return ezcMailPart
*/
private function generateHtmlPart()
{
$result = false;
if ( $this->htmlText != '' )
{
$matches = array();
if ( $this->options->automaticImageInclude === true )
{
// recognize file:// and file:///, pick out the image, add it as a part and then..:)
preg_match_all( "/<img[\s\*\s]src=[\'\"]file:\/\/([^ >\'\"]+)/i", $this->htmlText, $matches );
// pictures/files can be added multiple times. We only need them once.
$matches = array_unique( $matches[1] );
}
$result = new ezcMailText( $this->htmlText, $this->charset, $this->encoding );
$result->subType = "html";
if ( count( $matches ) > 0 )
{
$htmlPart = $result;
// wrap already existing message in an alternative part
$result = new ezcMailMultipartRelated( $result );
// create a filepart and add it to the related part
// also store the ID for each part since we need those
// when we replace the originals in the HTML message.
foreach ( $matches as $fileName )
{
if ( is_readable( $fileName ) )
{
// @todo waiting for fix of the fileinfo extension
// $contents = file_get_contents( $fileName );
$mimeType = null;
$contentType = null;
if ( ezcBaseFeatures::hasExtensionSupport( 'fileinfo' ) )
{
// if fileinfo extension is available
$filePart = new ezcMailFile( $fileName );
}
elseif ( ezcMailTools::guessContentType( $fileName, $contentType, $mimeType ) )
{
// if fileinfo extension is not available try to get content/mime type
// from the file extension
$filePart = new ezcMailFile( $fileName, $contentType, $mimeType );
}
else
{
// fallback in case fileinfo is not available and could not get content/mime
// type from file extension
$filePart = new ezcMailFile( $fileName, "application", "octet-stream" );
}
$cid = $result->addRelatedPart( $filePart );
// replace the original file reference with a reference to the cid
$this->htmlText = str_replace( 'file://' . $fileName, 'cid:' . $cid, $this->htmlText );
}
else
{
if ( file_exists( $fileName ) )
{
throw new ezcBaseFilePermissionException( $fileName, ezcBaseFileException::READ );
}
else
{
throw new ezcBaseFileNotFoundException( $fileName );
}
// throw
}
}
// update mail, with replaced URLs
$htmlPart->text = $this->htmlText;
}
}
return $result;
}
}
?>

View file

@ -0,0 +1,31 @@
<?php
/**
* File containing the ezcMailInvalidLimitException class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* The ezcMailInvalidLimitException is thrown when request is made to
* fetch messages with the offset outside of the existing message range.
*
* @package Mail
* @version //autogen//
*/
class ezcMailInvalidLimitException extends ezcMailException
{
/**
* Constructs an ezcMailInvalidLimitException
*
* @param mixed $offset
* @param mixed $count
*/
public function __construct( $offset, $count )
{
parent::__construct( "The message count '{$count}' is not allowed for the message subset '{$offset}', '{$count}'." );
}
}
?>

View file

@ -0,0 +1,29 @@
<?php
/**
* File containing the ezcMailException class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcMailExceptions are thrown when an exceptional state
* occures in the Mail package.
*
* @package Mail
* @version //autogen//
*/
class ezcMailException extends ezcBaseException
{
/**
* Constructs a new ezcMailException with error message $message.
*
* @param string $message
*/
public function __construct( $message )
{
parent::__construct( $message );
}
}
?>

View file

@ -0,0 +1,30 @@
<?php
/**
* File containing the ezcMailNoSuchMessageException class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* The ezcMailNoSuchMessageException is thrown when a message with an ID is
* requested that doesn't exist in the transport.
*
* @package Mail
* @version //autogen//
*/
class ezcMailNoSuchMessageException extends ezcMailException
{
/**
* Constructs an ezcMailNoSuchMessageException
*
* @param mixed $messageId
*/
public function __construct( $messageId )
{
parent::__construct( "The message with ID '{$messageId}' could not be found." );
}
}
?>

View file

@ -0,0 +1,31 @@
<?php
/**
* File containing the ezcMailOffsetOutOfRangeException class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* The ezcMailOffsetOutOfRangeException is thrown when request is made to
* fetch messages with the offset outside of the existing message range.
*
* @package Mail
* @version //autogen//
*/
class ezcMailOffsetOutOfRangeException extends ezcMailException
{
/**
* Constructs an ezcMailOffsetOutOfRangeException
*
* @param mixed $offset
* @param mixed $count
*/
public function __construct( $offset, $count )
{
parent::__construct( "The offset '{$offset}' is outside of the message subset '{$offset}', '{$count}'." );
}
}
?>

View file

@ -0,0 +1,30 @@
<?php
/**
* File containing the ezcMailTransportException class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Transport exceptions are thrown when either sending or receiving
* mail transports fail to do their job properly.
*
* @package Mail
* @version //autogen//
*/
class ezcMailTransportException extends ezcMailException
{
/**
* Constructs an ezcMailTransportException with low level information $message.
*
* @param string $message
*/
public function __construct( $message = '' )
{
parent::__construct( "An error occured while sending or receiving mail. " . $message );
}
}
?>

View file

@ -0,0 +1,34 @@
<?php
/**
* File containing the ezcMailTransportSmtpException class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @access private
*/
/**
* ezcMailTransportSmtpException is thrown when an exceptional state
* occures internally in the ezcMailSmtpTransport class. As it never enters
* "userspace" the class is marked as private.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailTransportSmtpException extends ezcMailException
{
/**
* Constructs an ezcMailTransportSmtpException with the highlevel error
* message $message.
*
* @param string $message
*/
public function __construct( $message )
{
parent::__construct( $message );
}
}
?>

View file

@ -0,0 +1,467 @@
<?php
/**
* File containing the ezcMailPart class.
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Abstract base class for all mail MIME parts.
*
* This base class provides functionality to store headers and to generate
* the mail part. Implementations of this class must handle the body of that
* parts themselves. They must also implement {@link generateBody()} which is
* called when the message part is generated.
*
* @property ezcMailContentDispositionHeader $contentDisposition
* Contains the information from the Content-Disposition field of
* this mail. This useful especially when you are investigating
* retrieved mail to see if a part is an attachment or should be
* displayed inline. However, it can also be used to set the same
* on outgoing mail. Note that the ezcMailFile part sets the
* Content-Disposition field itself based on it's own properties
* when sending mail.
* @property int $size
* The size of the mail part in bytes. It is set when parsing a
* mail {@link ezcMailParser->parseMail()}.
* @property-read ezcMailHeadersHolder $headers
* Contains the header holder object, taking care of the
* headers of this part. Can be retreived for reasons of
* extending this class and its derivals.
*
* @package Mail
* @version //autogen//
*/
abstract class ezcMailPart
{
/**
* An associative array containing all the headers set for this part.
*
* @var ezcMailHeadersHolder
*/
private $headers = null;
/**
* An associative array containing the charsets for the headers in this
* part.
*
* @var array(string=>string)
*/
private $headerCharsets = array();
/**
* An array of headers to exclude when generating the headers.
*
* @var array(string)
*/
private $excludeHeaders = array();
/**
* Holds the properties of this class.
*
* @var array(string=>mixed)
*/
protected $properties = array();
/**
* Constructs a new mail part.
*/
public function __construct()
{
$this->headers = new ezcMailHeadersHolder();
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @throws ezcBasePropertyPermissionException
* if the property is read-only.
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'contentDisposition':
case 'size':
$this->properties[$name] = $value;
break;
case 'headers':
throw new ezcBasePropertyPermissionException( $name, ezcBasePropertyPermissionException::READ );
default:
throw new ezcBasePropertyNotFoundException( $name );
}
}
/**
* Returns the property $name.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @return mixed
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'contentDisposition':
case 'size':
return isset( $this->properties[$name] ) ? $this->properties[$name] : null;
case "headers":
return $this->headers;
default:
throw new ezcBasePropertyNotFoundException( $name );
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'contentDisposition':
case 'size':
return isset( $this->properties[$name] );
case "headers":
return isset( $this->headers );
default:
return false;
}
}
/**
* Returns the RAW value of the header $name.
*
* Returns an empty string if the header is not found.
* Getting headers is case insensitive. Getting the header
* 'Message-Id' will match both 'Message-ID' and 'MESSAGE-ID'
* as well as 'Message-Id'.
*
* The raw value is MIME-encoded, so if you want to decode it,
* use {@link ezcMailTools::mimeDecode()} or implement your own
* MIME-decoding function.
*
* If $returnAllValues is true, the function will return all
* the values of the header $name from the mail in an array. If
* it is false it will return only the first value as a string
* if there are multiple values present in the mail.
*
* @param string $name
* @param bool $returnAllValues
* @return mixed
*/
public function getHeader( $name, $returnAllValues = false )
{
if ( isset( $this->headers[$name] ) )
{
if ( $returnAllValues === true )
{
return $this->headers[$name];
}
else if ( is_array( $this->headers[$name] ) )
{
// return only the first value in order to not break compatibility
// see issue #14257
return $this->headers[$name][0];
}
else
{
return $this->headers[$name];
}
}
return '';
}
/**
* Sets the header $name to the value $value and its charset to $charset.
*
* If the header is already set it will override the old value.
*
* Headers set should be folded at 76 or 998 characters according to
* the folding rules described in RFC 2822.
*
* If $charset is specified, it is associated with the header $name. It
* defaults to 'us-ascii' if not specified. The text in $value is encoded
* with $charset after calling generateHeaders().
*
* Note: The header Content-Disposition will be overwritten by the
* contents of the contentsDisposition property if set.
*
* @see generateHeaders()
*
* @param string $name
* @param string $value
* @param string $charset
*/
public function setHeader( $name, $value, $charset = 'us-ascii' )
{
$this->headers[$name] = $value;
$this->setHeaderCharset( $name, $charset );
}
/**
* Adds the headers $headers.
*
* The headers specified in the associative array $headers will overwrite
* any existing header values.
*
* The array $headers can have one of these 2 forms:
* - array( header_name => header_value ) - by default the 'us-ascii' charset
* will be associated with all headers
* - array( header_name => array( header_value, header_charset ) ) - if
* header_charset is missing it will default to 'us-ascii'
*
* Headers set should be folded at 76 or 998 characters according to
* the folding rules described in RFC 2822.
*
* @param array(string=>mixed) $headers
*/
public function setHeaders( array $headers )
{
foreach ( $headers as $key => $value )
{
if ( is_array( $value ) )
{
$this->headers[$key] = $value[0];
$charset = isset( $value[1] ) ? $value[1] : 'us-ascii';
$this->setHeaderCharset( $key, $charset );
}
else
{
$this->headers[$key] = $value;
$this->setHeaderCharset( $key );
}
}
}
/**
* Returns the headers set for this part as a RFC 822 string.
*
* Each header is separated by a line break.
* This method does not add the required two lines of space
* to separate the headers from the body of the part.
*
* It also encodes the headers (with the 'Q' encoding) if the charset
* associated with the header is different than 'us-ascii' or if it
* contains characters not allowed in mail headers.
*
* This function is called automatically by generate() and
* subclasses can override this method if they wish to set additional
* headers when the mail is generated.
*
* @see setHeader()
*
* @return string
*/
public function generateHeaders()
{
// set content disposition header
if ( $this->contentDisposition !== null &&
( $this->contentDisposition instanceof ezcMailContentDispositionHeader ) )
{
$cdHeader = $this->contentDisposition;
$cd = "{$cdHeader->disposition}";
if ( $cdHeader->fileName !== null )
{
$fileInfo = null;
if ( $cdHeader->fileNameCharSet !== null )
{
$fileInfo .= "*0*=\"{$cdHeader->fileNameCharSet}";
if ( $cdHeader->fileNameLanguage !== null )
{
$fileInfo .= "'{$cdHeader->fileNameLanguage}'";
}
else
{
// RFC 2184: the single quote delimiters MUST be present
// even when one of the field values is omitted
$fileInfo .= "''";
}
}
if ( $fileInfo !== null )
{
$cd .= "; filename{$fileInfo}{$cdHeader->fileName}\"";
}
else
{
$cd .= "; filename=\"{$cdHeader->fileName}\"";
}
}
if ( $cdHeader->creationDate !== null )
{
$cd .= "; creation-date=\"{$cdHeader->creationDate}\"";
}
if ( $cdHeader->modificationDate !== null )
{
$cd .= "; modification-date=\"{$cdHeader->modificationDate}\"";
}
if ( $cdHeader->readDate !== null )
{
$cd .= "; read-date=\"{$cdHeader->readDate}\"";
}
if ( $cdHeader->size !== null )
{
$cd .= "; size={$cdHeader->size}";
}
foreach ( $cdHeader->additionalParameters as $addKey => $addValue )
{
$cd .="; {$addKey}=\"{$addValue}\"";
}
$this->setHeader( 'Content-Disposition', $cd );
}
// generate headers
$text = "";
foreach ( $this->headers->getCaseSensitiveArray() as $header => $value )
{
if ( is_array( $value ) )
{
$value = $value[0];
}
// here we encode every header, even the ones that we don't add to
// the header set directly. We do that so that transports sill see
// all the encoded headers which they then can use accordingly.
$charset = $this->getHeaderCharset( $header );
switch ( strtolower( $charset ) )
{
case 'us-ascii':
$value = ezcMailHeaderFolder::foldAny( $value );
break;
case 'iso-8859-1': case 'iso-8859-2': case 'iso-8859-3': case 'iso-8859-4':
case 'iso-8859-5': case 'iso-8859-6': case 'iso-8859-7': case 'iso-8859-8':
case 'iso-8859-9': case 'iso-8859-10': case 'iso-8859-11': case 'iso-8859-12':
case 'iso-8859-13': case 'iso-8859-14': case 'iso-8859-15' :case 'iso-8859-16':
case 'windows-1250': case 'windows-1251': case 'windows-1252':
case 'utf-8':
if ( strpbrk( $value, "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" ) === false )
{
$value = ezcMailHeaderFolder::foldAny( $value );
break;
}
// break intentionally missing
default:
$preferences = array(
'input-charset' => $charset,
'output-charset' => $charset,
'line-length' => ezcMailHeaderFolder::getLimit(),
'scheme' => 'Q',
'line-break-chars' => ezcMailTools::lineBreak()
);
$value = iconv_mime_encode( 'dummy', $value, $preferences );
$value = substr( $value, 7 ); // "dummy: " + 1
// just to keep compatibility with code which might read
// the headers after generateHeaders() has been called
$this->setHeader( $header, $value, $charset );
break;
}
if ( in_array( strtolower( $header ), $this->excludeHeaders ) === false )
{
$text .= "$header: $value" . ezcMailTools::lineBreak();
}
}
return $text;
}
/**
* The array $headers will be excluded when the headers are generated.
*
* @see generateHeaders()
*
* @param array(string) $headers
*/
public function appendExcludeHeaders( array $headers )
{
$lowerCaseHeaders = array();
foreach ( $headers as $header )
{
$lowerCaseHeaders[] = strtolower( $header );
}
$this->excludeHeaders = array_merge( $this->excludeHeaders, $lowerCaseHeaders );
}
/**
* Returns the body of this part as a string.
*
* This method is called automatically by generate() and subclasses must
* implement it.
*
* @return string
*/
abstract public function generateBody();
/**
* Returns the complete mail part including both the header and the body
* as a string.
*
* @return string
*/
public function generate()
{
return $this->generateHeaders() . ezcMailTools::lineBreak() . $this->generateBody();
}
/**
* Returns the charset registered for the header $name.
*
* @param string $name
* @return string
*/
protected function getHeaderCharset( $name )
{
if ( isset( $this->headerCharsets[$name] ) )
{
return $this->headerCharsets[$name];
}
// if no charset is set then return 'us-ascii'
return 'us-ascii';
}
/**
* Sets the charset of the header $name to $value.
*
* If $value is not specified it defaults to 'us-ascii'.
*
* @param string $name
* @param string $value
*/
protected function setHeaderCharset( $name, $value = 'us-ascii' )
{
$this->headerCharsets[$name] = $value;
}
}
?>

View file

@ -0,0 +1,28 @@
<?php
/**
* File containing the ezcMailTransport class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Interface for classes that implement a mail transport.
*
* Subclasses must implement the send() method.
*
* @package Mail
* @version //autogen//
*/
interface ezcMailTransport
{
/**
* Sends the contents of $mail.
*
* @param ezcMail $mail
*/
public function send( ezcMail $mail );
}
?>

View file

@ -0,0 +1,129 @@
<?php
/**
* File containing the ezcMailCharsetConverter class.
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Class containing common character set conversion methods.
*
* By calling the static function ezcMailCharsetConverter::setConvertMethod()
* before doing mail parsing, another callback function can be used for
* character conversion to UTF-8 in place of the normal iconv() conversion.
*
* The callback function must have this signature:
* <code>
* public static function function_name( $text, $originalCharset );
* </code>
*
* where:
* - $text = string to convert to UTF-8
* - $originalCharset = in what charset is $text
*
* Example:
* <code>
* // specify another function for character set conversion
* ezcMailCharsetConverter::setConvertMethod( array( 'myConverter', 'convertToUTF8IconvIgnore' ) );
*
* // ...code for mail parsing...
* </code>
*
* where myConverter is (along with some other examples of charset conversion
* functions which can be used):
* <code>
* class myConverter
* {
* public static function convertToUTF8IconvIgnore( $text, $originalCharset )
* {
* if ( $originalCharset === 'unknown-8bit' || $originalCharset === 'x-user-defined' )
* {
* $originalCharset = "latin1";
* }
* return iconv( $originalCharset, 'utf-8//IGNORE', $text );
* }
*
* public static function convertToUTF8IconvTranslit( $text, $originalCharset )
* {
* if ( $originalCharset === 'unknown-8bit' || $originalCharset === 'x-user-defined' )
* {
* $originalCharset = "latin1";
* }
* return iconv( $originalCharset, 'utf-8//TRANSLIT', $text );
* }
*
* public static function convertToUTF8Mbstring( $text, $originalCharset )
* {
* return mb_convert_encoding( $text, "UTF-8", $originalCharset );
* }
* }
* </code>
*
* Developers can choose to use the error suppresion operator ('@') in front of
* the iconv() calls in the above examples, in order to ignore the notices thrown
* when processing broken text (issue #8369).
*
* @package Mail
* @version //autogen//
*/
class ezcMailCharsetConverter
{
/**
* Callback function to use for character set conversion to UTF8.
*
* @var callback
*/
private static $method = array( __CLASS__, 'convertToUTF8Iconv' );
/**
* Sets the callback function used for character set conversion to UTF-8.
*
* Call this method before doing mail parsing if you need a special way
* of converting the character set to UTF-8.
*
* @param callback $method
*/
public static function setConvertMethod( $method )
{
self::$method = $method;
}
/**
* Converts the $text with the charset $originalCharset to UTF-8.
*
* It calls the function specified by using the static method
* setConvertMethod(). By default it calls convertToUTF8Iconv() defined
* in this class.
*
* @param string $text
* @param string $originalCharset
* @return string
*/
public static function convertToUTF8( $text, $originalCharset )
{
return call_user_func( self::$method, $text, $originalCharset );
}
/**
* Converts the $text with the charset $originalCharset to UTF-8.
*
* In case $originalCharset is 'unknown-8bit' or 'x-user-defined' then
* it is assumed to be 'latin1' (ISO-8859-1).
*
* @param string $text
* @param string $originalCharset
* @return string
*/
public static function convertToUTF8Iconv( $text, $originalCharset )
{
if ( $originalCharset === 'unknown-8bit' || $originalCharset === 'x-user-defined' )
{
$originalCharset = "latin1";
}
return iconv( $originalCharset, 'utf-8', $text );
}
}
?>

View file

@ -0,0 +1,146 @@
<?php
/**
* File containing the ezcMailHeaderFolder class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @access private
*/
/**
* Internal class folding headers according to RFC 2822.
*
* RFC 2822 specifies two line length restrictions:
*
* "There are two limits that this standard places on the number of
* characters in a line. Each line of characters MUST be no more than
* 998 characters, and SHOULD be no more than 78 characters, excluding
* the CRLF."
*
* The 76 character limit is because of readability. The 998 character limit
* is a result of SMTP limitations.
*
* The rule for folding is:
* "wherever this standard allows for folding white space (not
* simply WSP characters), a CRLF may be inserted before any WSP."
*
* This is described in more detail in section 3.2.3.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailHeaderFolder
{
/**
* The soft limit of 76 characters per line.
*/
const SOFT_LIMIT = 76;
/**
* The soft limit of 998 characters per line.
*/
const HARD_LIMIT = 998;
/**
* The default folding limit.
*
* @var int
*/
static private $limit = 76;
/**
* Sets the number of allowed characters before folding to $numCharacters.
*
* $numCharacters must be one of:
* - ezcMailHeaderFolder::SOFT_LIMIT (76 characters)
* - ezcMailHeaderFolder::HARD_LIMIT (998 characters)
*
* @param int $numCharacters
*/
static public function setLimit( $numCharacters )
{
self::$limit = $numCharacters;
}
/**
* Returns the maximum number of characters allowed per line.
*
* @return int
*/
static public function getLimit()
{
return self::$limit;
}
/**
* Returns $text folded to the 998 character limit on any whitespace.
*
* The algorithm tries to minimize the number of comparisons by searching
* backwards from the maximum number of allowed characters on a line.
*
* @param string $text
* @return string
*/
static public function foldAny( $text )
{
// Don't fold unless we have to.
if ( strlen( $text ) <= self::$limit )
{
return $text;
}
// go to 998'th char.
// search back to whitespace
// fold
$length = strlen( $text );
$folded = "";
// find first occurence of whitespace searching backwards
$search = 0;
$previousFold = 0;
while ( ( $search + self::$limit ) < $length )
{
// search from the max possible length of the substring
$search += self::$limit;
while ( $text[$search] != " " && $text[$search] != "\t" && $search > $previousFold )
{
$search--;
}
if ( $search == $previousFold )
{
// continuous string of more than limit chars.
// We will just have to continue searching forwards to the next whitespace instead
// This is not confirming to standard.. but what can we do?
$search += self::$limit; // back to where we started
while ( $search < $length && $text[$search] != " " && $text[$search] != "\t" )
{
$search++;
}
}
// lets fold
if ( $folded === "" )
{
$folded = substr( $text, $previousFold, $search - $previousFold );
}
else
{
$folded .= ezcMailTools::lineBreak() .
substr( $text, $previousFold, $search - $previousFold );
}
$previousFold = $search;
}
// we need to append the rest if there is any
if ( $search < $length )
{
$folded .= ezcMailTools::lineBreak() . substr( $text, $search );
}
return $folded;
}
}
?>

View file

@ -0,0 +1,517 @@
<?php
/**
* File containing the ezcMail class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* The main mail class.
*
* You can use ezcMail together with the other classes derived from ezcMailPart
* to build email messages. When the mail is built, use the Transport classes
* to send the mail.
*
* This example builds and sends a simple text mail message:
* <code>
* $mail = new ezcMail;
* $mail->from = new ezcMailAddress( 'sender@example.com', 'Adrian Ripburger' );
* $mail->addTo( new ezcMailAddress( 'receiver@example.com', 'Maureen Corley' ) );
* $mail->subject = "Hi";
* $mail->body = new ezcMailText( "I just mail to say I love you!" );
* $transport = new ezcMailMtaTransport();
* $transport->send( $mail );
* </code>
*
* You can also derive your own mail classes from this class if you have
* special requirements. An example of this is the ezcMailComposer class which
* is a convenience class to send simple mail structures and HTML mail.
*
* There are several headers you can set on the mail object to achieve various
* effects:
* - Reply-To - Set this to an email address if you want people to reply to an
* address other than the from address.
* - Errors-To - If the mail can not be delivered the error message will be
* sent to this address.
*
* @property ezcMailAddress $from Contains the from address as an
* ezcMailAddress object.
* @property array(ezcMailAddress) $to Contains an array of ezcMailAddress objects.
* @property array(ezcMailAddress) $cc Contains an array of ezcMailAddress objects.
* @property array(ezcMailAddress) $bcc Contains an array of ezcMailAddress objects.
* @property string $subject
* Contains the subject of the e-mail.
* Use setSubject if you require a
* special encoding.
* @property string $subjectCharset
* The encoding of the subject.
* @property ezcMailPart $body The body part of the message.
*
* @property-read string $messageId
* The message ID of the message. Treat
* as read-only unless you're 100% sure
* what you're doing. Also accessible through
* the deprecated property messageID.
* @property-read integer $timestamp
* The date/time of when the message was
* sent as Unix Timestamp.
* @property ezcMailAddress $returnPath Contains the Return-Path address as an
* ezcMailAddress object.
*
* @apichange Remove the support for the deprecated property messageID.
*
* @package Mail
* @version //autogen//
* @mainclass
*/
class ezcMail extends ezcMailPart
{
/**
* 7 bit encoding.
*/
const SEVEN_BIT = "7bit";
/**
* 8 bit encoding.
*/
const EIGHT_BIT = "8bit";
/**
* Binary encoding.
*/
const BINARY = "binary";
/**
* Quoted printable encoding.
*/
const QUOTED_PRINTABLE = "quoted-printable";
/**
* Base 64 encoding.
*/
const BASE64 = "base64";
/**
* Constructs an empty ezcMail object.
*/
public function __construct()
{
parent::__construct();
$this->properties['from'] = null;
$this->properties['to'] = array();
$this->properties['cc'] = array();
$this->properties['bcc'] = array();
$this->properties['subject'] = null;
$this->properties['subjectCharset'] = 'us-ascii';
$this->properties['body'] = null;
$this->properties['messageId'] = null;
$this->properties['returnPath'] = null;
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @throws ezcBasePropertyPermissionException
* if the property is read-only.
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'from':
case 'returnPath':
if ( $value !== null && !$value instanceof ezcMailAddress )
{
throw new ezcBaseValueException( $name, $value, 'ezcMailAddress or null' );
}
$this->properties[$name] = $value;
break;
case 'to':
case 'cc':
case 'bcc':
if ( !is_array( $value ) )
{
throw new ezcBaseValueException( $name, $value, 'array( ezcMailAddress )' );
}
foreach ( $value as $key => $obj )
{
if ( !$obj instanceof ezcMailAddress )
{
throw new ezcBaseValueException( "{$name}[{$key}]", $obj, 'ezcMailAddress' );
}
}
$this->properties[$name] = $value;
break;
case 'subject':
$this->properties['subject'] = trim( $value );
break;
case 'subjectCharset':
$this->properties['subjectCharset'] = $value;
break;
case 'body':
if ( !$value instanceof ezcMailPart )
{
throw new ezcBaseValueException( $name, $value, 'ezcMailPart' );
}
$this->properties['body'] = $value;
break;
case 'messageId':
case 'messageID':
$this->properties['messageId'] = $value;
break;
case 'timestamp':
throw new ezcBasePropertyPermissionException( $name, ezcBasePropertyPermissionException::READ );
break;
default:
parent::__set( $name, $value );
break;
}
}
/**
* Returns the property $name.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @return mixed
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'to':
case 'cc':
case 'bcc':
return (array) $this->properties[$name];
case 'from':
case 'subject':
case 'subjectCharset':
case 'body':
case 'messageId':
case 'returnPath':
return $this->properties[$name];
case 'messageID': // deprecated version
return $this->properties['messageId'];
case 'timestamp':
return strtotime( $this->getHeader( "Date" ) );
default:
return parent::__get( $name );
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'to':
case 'cc':
case 'bcc':
case 'from':
case 'subject':
case 'subjectCharset':
case 'body':
case 'messageId':
case 'returnPath':
return isset( $this->properties[$name] );
case 'messageID': // deprecated version
return isset( $this->properties['messageId'] );
case 'timestamp':
return $this->getHeader( "Date" ) != null;
default:
return parent::__isset( $name );
}
}
/**
* Adds the ezcMailAddress $address to the list of 'to' recipients.
*
* @param ezcMailAddress $address
*/
public function addTo( ezcMailAddress $address )
{
$this->properties['to'][] = $address;
}
/**
* Adds the ezcMailAddress $address to the list of 'cc' recipients.
*
* @param ezcMailAddress $address
*/
public function addCc( ezcMailAddress $address )
{
$this->properties['cc'][] = $address;
}
/**
* Adds the ezcMailAddress $address to the list of 'bcc' recipients.
*
* @param ezcMailAddress $address
*/
public function addBcc( ezcMailAddress $address )
{
$this->properties['bcc'][] = $address;
}
/**
* Returns the generated body part of this mail.
*
* Returns an empty string if no body has been set.
*
* @return string
*/
public function generateBody()
{
if ( is_subclass_of( $this->body, 'ezcMailPart' ) )
{
return $this->body->generateBody();
}
return '';
}
/**
* Returns the generated headers for the mail.
*
* This method is called automatically when the mail message is built.
* You can re-implement this method in subclasses if you wish to set
* different mail headers than ezcMail.
*
* @return string
*/
public function generateHeaders()
{
// set our headers first.
if ( $this->from !== null )
{
$this->setHeader( "From", ezcMailTools::composeEmailAddress( $this->from ) );
}
if ( $this->to !== null )
{
$this->setHeader( "To", ezcMailTools::composeEmailAddresses( $this->to ) );
}
if ( count( $this->cc ) )
{
$this->setHeader( "Cc", ezcMailTools::composeEmailAddresses( $this->cc ) );
}
if ( count( $this->bcc ) )
{
$this->setHeader( "Bcc", ezcMailTools::composeEmailAddresses( $this->bcc ) );
}
$this->setHeader( 'Subject', $this->subject, $this->subjectCharset );
$this->setHeader( 'MIME-Version', '1.0' );
$this->setHeader( 'User-Agent', 'eZ Components' );
$this->setHeader( 'Date', date( 'r' ) );
$idhost = $this->from != null && $this->from->email != '' ? $this->from->email : 'localhost';
if ( is_null( $this->messageId ) )
{
$this->setHeader( 'Message-Id', '<' . ezcMailTools::generateMessageId( $idhost ) . '>' );
}
else
{
$this->setHeader( 'Message-Id', $this->messageID );
}
// if we have a body part, include the headers of the body
if ( is_subclass_of( $this->body, "ezcMailPart" ) )
{
return parent::generateHeaders() . $this->body->generateHeaders();
}
return parent::generateHeaders();
}
/**
* Returns an array of mail parts from the current mail.
*
* The array returned contains objects of classes:
* - ezcMailText
* - ezcMailFile
* - ezcMailRfc822Digest
* If the method is called with $includeDigests as true, then the returned
* array will not contain ezcMailRfc822Digest objects, but instead the mail
* parts inside the digests.
* The parameter $filter can be used to restrict the returned mail parts,
* eg. $filter = array( 'ezcMailFile' ) to return only file mail parts.
*
* A typical use for this function is to get a list of attachments from a mail.
* Example:
* <code>
* // $mail is an ezcMail object
* $parts = $mail->fetchParts();
* // after the above line is executed, $parts will contain an array of mail parts objects,
* // for example one ezcMailText object ($parts[0]) and two ezcMailRfc822Digest objects ($parts[1] and $parts[2]).
* // the ezcMailText object will be used to render the mail text, and the
* // other two objects will be displayed as links ("view attachment")
*
* // when user clicks on one of the two attachments, the parts of that attachment
* // must be retrieved in order to render the attached digest:
* $subparts = $parts[1]->mail->fetchParts();
* // after the above line is executed, $subparts will contain an array of mail parts objects,
* // for example one ezcMailText object and one ezcMailFile object
* </code>
*
* @param array(string) $filter
* @param bool $includeDigests
* @return array(ezcMailPart)
*/
public function fetchParts( $filter = null, $includeDigests = false )
{
$context = new ezcMailPartWalkContext( array( __CLASS__, 'collectPart' ) );
$context->includeDigests = $includeDigests;
$context->filter = $filter;
$context->level = 0;
$this->walkParts( $context, $this );
return $context->getParts();
}
/**
* Walks recursively through the mail parts in the specified mail object.
*
* $context is an object of class ezcMailPartWalkContext, which must contain
* a valid callback function name to be applied to all mail parts. You can use
* the collectPart() method, or create your own callback function which can
* for example save the mail parts to disk or to a database.
*
* For the properties you can set to the walk context see: {@link ezcMailPartWalkContext}
*
* Example:
* <code>
* class App
* {
* public static function saveMailPart( $context, $mailPart )
* {
* // code to save the $mailPart object to disk
* }
* }
*
* // use the saveMailPart() function as a callback in walkParts()
* // where $mail is an ezcMail object.
* $context = new ezcMailPartWalkContext( array( 'App', 'saveMailPart' ) );
* $context->includeDigests = true; // if you want to go through the digests in the mail
* $mail->walkParts( $context, $mail );
* </code>
*
* @param ezcMailPartWalkContext $context
* @param ezcMailPart $mail
*/
public function walkParts( ezcMailPartWalkContext $context, ezcMailPart $mail )
{
$className = get_class( $mail );
$context->level++;
switch ( $className )
{
case 'ezcMail':
case 'ezcMailComposer':
if ( $mail->body !== null )
{
$this->walkParts( $context, $mail->body );
}
break;
case 'ezcMailMultipartMixed':
case 'ezcMailMultipartAlternative':
case 'ezcMailMultipartDigest':
case 'ezcMailMultipartReport':
foreach ( $mail->getParts() as $part )
{
$this->walkParts( $context, $part );
}
break;
case 'ezcMailMultipartRelated':
$this->walkParts( $context, $mail->getMainPart() );
foreach ( $mail->getRelatedParts() as $part )
{
$this->walkParts( $context, $part );
}
break;
case 'ezcMailRfc822Digest':
if ( $context->includeDigests )
{
$this->walkParts( $context, $mail->mail );
}
elseif ( empty( $context->filter ) || in_array( $className, $context->filter ) )
{
call_user_func( $context->callbackFunction, $context, $mail );
}
break;
case 'ezcMailText':
case 'ezcMailFile':
case 'ezcMailDeliveryStatus':
if ( empty( $context->filter ) || in_array( $className, $context->filter ) )
{
call_user_func( $context->callbackFunction, $context, $mail );
}
break;
default:
// for cases where a custom mail class has been specified with $parser->options->mailClass
if ( in_array( 'ezcMail', class_parents( $className ) ) )
{
if ( $mail->body !== null )
{
$this->walkParts( $context, $mail->body );
}
}
// for cases where a custom file class has been specified with $parser->options->fileClass
if ( in_array( 'ezcMailFile', class_parents( $className ) ) )
{
if ( empty( $context->filter ) || in_array( $className, $context->filter ) )
{
call_user_func( $context->callbackFunction, $context, $mail );
}
}
}
$context->level--;
}
/**
* Saves $mail in the $context object.
*
* This function is used as a callback in the fetchParts() method.
*
* @param ezcMailPartWalkContext $context
* @param ezcMailPart $mail
*/
protected static function collectPart( ezcMailPartWalkContext $context, ezcMailPart $mail )
{
$context->appendPart( $mail );
}
}
?>

View file

@ -0,0 +1,81 @@
<?php
/**
* Autoloader definition for the Mail component.
*
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @version //autogentag//
* @filesource
* @package Mail
*/
return array(
'ezcMailException' => 'Mail/exceptions/mail_exception.php',
'ezcMailInvalidLimitException' => 'Mail/exceptions/invalid_limit.php',
'ezcMailNoSuchMessageException' => 'Mail/exceptions/no_such_message.php',
'ezcMailOffsetOutOfRangeException' => 'Mail/exceptions/offset_out_of_range.php',
'ezcMailTransportException' => 'Mail/exceptions/transport_exception.php',
'ezcMailTransportSmtpException' => 'Mail/exceptions/transport_smtp_exception.php',
'ezcMailPart' => 'Mail/interfaces/part.php',
'ezcMailPartParser' => 'Mail/parser/interfaces/part_parser.php',
'ezcMailTransport' => 'Mail/interfaces/transport.php',
'ezcMail' => 'Mail/mail.php',
'ezcMailFilePart' => 'Mail/parts/file.php',
'ezcMailMtaTransport' => 'Mail/transports/mta/mta_transport.php',
'ezcMailMultipart' => 'Mail/parts/multipart.php',
'ezcMailMultipartParser' => 'Mail/parser/parts/multipart_parser.php',
'ezcMailParserSet' => 'Mail/parser/interfaces/parser_set.php',
'ezcMailSmtpTransport' => 'Mail/transports/smtp/smtp_transport.php',
'ezcMailTransportOptions' => 'Mail/options/transport_options.php',
'ezcMailAddress' => 'Mail/structs/mail_address.php',
'ezcMailCharsetConverter' => 'Mail/internal/charset_convert.php',
'ezcMailComposer' => 'Mail/composer.php',
'ezcMailComposerOptions' => 'Mail/options/composer_options.php',
'ezcMailContentDispositionHeader' => 'Mail/structs/content_disposition_header.php',
'ezcMailDeliveryStatus' => 'Mail/parts/delivery_status.php',
'ezcMailDeliveryStatusParser' => 'Mail/parser/parts/delivery_status_parser.php',
'ezcMailFile' => 'Mail/parts/fileparts/disk_file.php',
'ezcMailFileParser' => 'Mail/parser/parts/file_parser.php',
'ezcMailFileSet' => 'Mail/transports/file/file_set.php',
'ezcMailHeaderFolder' => 'Mail/internal/header_folder.php',
'ezcMailHeadersHolder' => 'Mail/parser/headers_holder.php',
'ezcMailImapSet' => 'Mail/transports/imap/imap_set.php',
'ezcMailImapSetOptions' => 'Mail/options/imap_set_options.php',
'ezcMailImapTransport' => 'Mail/transports/imap/imap_transport.php',
'ezcMailImapTransportOptions' => 'Mail/options/imap_options.php',
'ezcMailMboxSet' => 'Mail/transports/mbox/mbox_set.php',
'ezcMailMboxTransport' => 'Mail/transports/mbox/mbox_transport.php',
'ezcMailMultipartAlternative' => 'Mail/parts/multiparts/multipart_alternative.php',
'ezcMailMultipartAlternativeParser' => 'Mail/parser/parts/multipart_alternative_parser.php',
'ezcMailMultipartDigest' => 'Mail/parts/multiparts/multipart_digest.php',
'ezcMailMultipartDigestParser' => 'Mail/parser/parts/multipart_digest_parser.php',
'ezcMailMultipartMixed' => 'Mail/parts/multiparts/multipart_mixed.php',
'ezcMailMultipartMixedParser' => 'Mail/parser/parts/multipart_mixed_parser.php',
'ezcMailMultipartRelated' => 'Mail/parts/multiparts/multipart_related.php',
'ezcMailMultipartRelatedParser' => 'Mail/parser/parts/multipart_related_parser.php',
'ezcMailMultipartReport' => 'Mail/parts/multiparts/multipart_report.php',
'ezcMailMultipartReportParser' => 'Mail/parser/parts/multipart_report_parser.php',
'ezcMailParser' => 'Mail/parser/parser.php',
'ezcMailParserOptions' => 'Mail/options/parser_options.php',
'ezcMailParserShutdownHandler' => 'Mail/parser/shutdown_handler.php',
'ezcMailPartWalkContext' => 'Mail/structs/walk_context.php',
'ezcMailPop3Set' => 'Mail/transports/pop3/pop3_set.php',
'ezcMailPop3Transport' => 'Mail/transports/pop3/pop3_transport.php',
'ezcMailPop3TransportOptions' => 'Mail/options/pop3_options.php',
'ezcMailRfc2231Implementation' => 'Mail/parser/rfc2231_implementation.php',
'ezcMailRfc822Digest' => 'Mail/parts/rfc822_digest.php',
'ezcMailRfc822DigestParser' => 'Mail/parser/parts/rfc822_digest_parser.php',
'ezcMailRfc822Parser' => 'Mail/parser/parts/rfc822_parser.php',
'ezcMailSmtpTransportOptions' => 'Mail/options/smtp_options.php',
'ezcMailStorageSet' => 'Mail/transports/storage/storage_set.php',
'ezcMailStreamFile' => 'Mail/parts/fileparts/stream_file.php',
'ezcMailText' => 'Mail/parts/text.php',
'ezcMailTextParser' => 'Mail/parser/parts/text_parser.php',
'ezcMailTools' => 'Mail/tools.php',
'ezcMailTransportConnection' => 'Mail/transports/transport_connection.php',
'ezcMailTransportMta' => 'Mail/transports/mta/transport_mta.php',
'ezcMailTransportSmtp' => 'Mail/transports/smtp/transport_smtp.php',
'ezcMailVariableSet' => 'Mail/transports/variable/var_set.php',
'ezcMailVirtualFile' => 'Mail/parts/fileparts/virtual_file.php',
);
?>

View file

@ -0,0 +1,83 @@
<?php
/**
* File containing the ezcMailComposerOptions class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Class containing the options for the mail composer.
*
* Example of how to use the composer options:
* <code>
* $options = new ezcMailComposerOptions();
* $options->automaticImageInclude = false; // default value is true
*
* $mail = new ezcMailComposer( $options );
* </code>
*
* Alternatively, you can set the options direcly:
* <code>
* $mail = new ezcMailComposer();
* $mail->options->automaticImageInclude = false;
* </code>
*
* @property bool $automaticImageInclude
* Specifies whether to include in the generated mail the content of
* the files specified with "file://" in image tags. Default value
* is true (the contents are included).
*
* @package Mail
* @version //autogen//
*/
class ezcMailComposerOptions extends ezcBaseOptions
{
/**
* Constructs an object with the specified values.
*
* @throws ezcBasePropertyNotFoundException
* if $options contains a property not defined
* @throws ezcBaseValueException
* if $options contains a property with a value not allowed
* @param array(string=>mixed) $options
*/
public function __construct( array $options = array() )
{
$this->automaticImageInclude = true; // default is to include the contents of "file://" from image tags
parent::__construct( $options );
}
/**
* Sets the option $propertyName to $propertyValue.
*
* @throws ezcBasePropertyNotFoundException
* if the property $propertyName is not defined
* @throws ezcBaseValueException
* if $propertyValue is not correct for the property $propertyName
* @param string $propertyName
* @param mixed $propertyValue
* @ignore
*/
public function __set( $propertyName, $propertyValue )
{
switch ( $propertyName )
{
case 'automaticImageInclude':
if ( !is_bool( $propertyValue ) )
{
throw new ezcBaseValueException( $propertyName, $propertyValue, 'bool' );
}
$this->properties[$propertyName] = $propertyValue;
break;
default:
throw new ezcBasePropertyNotFoundException( $propertyName );
}
}
}
?>

View file

@ -0,0 +1,79 @@
<?php
/**
* File containing the ezcMailImapTransportOptions class.
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Class containing the options for IMAP transport.
*
* The options from {@link ezcMailTransportOptions} are inherited.
*
* Example of how to use IMAP transport options:
* <code>
* $options = new ezcMailImapTransportOptions();
* $options->ssl = true;
* $options->timeout = 3;
* $options->uidReferencing = true;
*
* $imap = new ezcMailImapTransport( 'imap.example.com', null, $options );
* </code>
*
* @property bool $uidReferencing
* Specifies if the IMAP commands will operate with message unique
* IDs or with message numbers (default).
*
* @package Mail
* @version //autogen//
*/
class ezcMailImapTransportOptions extends ezcMailTransportOptions
{
/**
* Constructs an object with the specified values.
*
* @throws ezcBasePropertyNotFoundException
* if $options contains a property not defined
* @throws ezcBaseValueException
* if $options contains a property with a value not allowed
* @param array(string=>mixed) $options
*/
public function __construct( array $options = array() )
{
$this->uidReferencing = false;
parent::__construct( $options );
}
/**
* Sets the value of the option $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property $name is not defined
* @throws ezcBaseValueException
* if $value is not correct for the property $name
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'uidReferencing':
if ( !is_bool( $value ) )
{
throw new ezcBaseValueException( $name, $value, 'bool' );
}
$this->properties[$name] = $value;
break;
default:
parent::__set( $name, $value );
}
}
}
?>

View file

@ -0,0 +1,67 @@
<?php
/**
* File containing the ezcMailImapSetOptions class.
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Class containing the options for IMAP mail set.
*
* @property bool $uidReferencing
* Specifies if the IMAP commands will operate with message unique
* IDs or with message numbers (default).
*
* @package Mail
* @version //autogen//
*/
class ezcMailImapSetOptions extends ezcBaseOptions
{
/**
* Constructs an object with the specified values.
*
* @throws ezcBasePropertyNotFoundException
* if $options contains a property not defined
* @throws ezcBaseValueException
* if $options contains a property with a value not allowed
* @param array(string=>mixed) $options
*/
public function __construct( array $options = array() )
{
$this->uidReferencing = false;
parent::__construct( $options );
}
/**
* Sets the value of the option $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property $name is not defined
* @throws ezcBaseValueException
* if $value is not correct for the property $name
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'uidReferencing':
if ( !is_bool( $value ) )
{
throw new ezcBaseValueException( $name, $value, 'bool' );
}
$this->properties[$name] = $value;
break;
default:
throw new ezcBasePropertyNotFoundException( $name );
}
}
}
?>

View file

@ -0,0 +1,132 @@
<?php
/**
* File containing the ezcMailParserOption class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Class containing the basic options for the mail parser.
*
* Example of how to use the parser options:
* <code>
* $options = new ezcMailParserOptions();
* $options->mailClass = 'myCustomMailClass'; // extends ezcMail
* $options->fileClass = 'myCustomFileClass'; // extends ezcMailFile
* $options->parseTextAttachmentsAsFiles = true; // to get the text attachments in ezcMailFile objects
*
* $parser = new ezcMailParser( $options );
* </code>
*
* Another way to specify the options is:
* <code>
* $parser = new ezcMailParser();
* $parser->options->mailClass = 'myCustomMailClass'; // extends ezcMail
* $parser->options->fileClass = 'myCustomFileClass'; // extends ezcMailFile
* $parser->options->parseTextAttachmentsAsFiles = true;
* </code>
*
* @property string $mailClass
* Specifies a class descending from ezcMail which can be returned by the
* parser if you plan to use another class instead of ezcMail. The default
* value is ezcMail.
* @property string $fileClass
* Specifies a class descending from ezcMailFile which can be instanciated
* by the parser to handle file attachments. The default value is
* ezcMailFile.
* @property string $parseTextAttachmentsAsFiles
* Specifies whether to parse the text attachments in an ezcMailTextPart
* (default) or in an ezcMailFile (by setting the option to true).
* @package Mail
* @version //autogen//
*/
class ezcMailParserOptions extends ezcBaseOptions
{
/**
* Constructs an object with the specified values.
*
* @throws ezcBasePropertyNotFoundException
* if $options contains a property not defined
* @throws ezcBaseValueException
* if $options contains a property with a value not allowed
* @param array(string=>mixed) $options
*/
public function __construct( array $options = array() )
{
$this->mailClass = 'ezcMail'; // default value for mail class is 'ezcMail'
$this->fileClass = 'ezcMailFile'; // default value for file attachment class is 'ezcMailFile'
$this->parseTextAttachmentsAsFiles = false; // default is to parse text attachments in ezcMailTextPart objects
parent::__construct( $options );
}
/**
* Sets the option $propertyName to $propertyValue.
*
* @throws ezcBasePropertyNotFoundException
* if the property $propertyName is not defined
* @throws ezcBaseValueException
* if $propertyValue is not correct for the property $propertyName
* @throws ezcBaseInvalidParentClassException
* if the class name passed as replacement mailClass does not
* inherit from ezcMail.
* @throws ezcBaseInvalidParentClassException
* if the class name passed as replacement fileClass does not
* inherit from ezcMailFile.
* @param string $propertyName
* @param mixed $propertyValue
* @ignore
*/
public function __set( $propertyName, $propertyValue )
{
switch ( $propertyName )
{
case 'mailClass':
if ( !is_string( $propertyValue ) )
{
throw new ezcBaseValueException( $propertyName, $propertyValue, 'string that contains a class name' );
}
// Check if the passed classname actually implements the
// correct parent class.
if ( 'ezcMail' !== $propertyValue && !in_array( 'ezcMail', class_parents( $propertyValue ) ) )
{
throw new ezcBaseInvalidParentClassException( 'ezcMail', $propertyValue );
}
$this->properties[$propertyName] = $propertyValue;
break;
case 'fileClass':
if ( !is_string( $propertyValue ) )
{
throw new ezcBaseValueException( $propertyName, $propertyValue, 'string that contains a class name' );
}
// Check if the passed classname actually implements the
// correct parent class.
if ( 'ezcMailFile' !== $propertyValue && !in_array( 'ezcMailFile', class_parents( $propertyValue ) ) )
{
throw new ezcBaseInvalidParentClassException( 'ezcMailFile', $propertyValue );
}
$this->properties[$propertyName] = $propertyValue;
ezcMailFileParser::$fileClass = $propertyValue;
break;
case 'parseTextAttachmentsAsFiles':
if ( !is_bool( $propertyValue ) )
{
throw new ezcBaseValueException( $propertyName, $propertyValue, 'bool' );
}
$this->properties[$propertyName] = $propertyValue;
ezcMailPartParser::$parseTextAttachmentsAsFiles = $propertyValue;
break;
default:
throw new ezcBasePropertyNotFoundException( $propertyName );
}
}
}
?>

View file

@ -0,0 +1,81 @@
<?php
/**
* File containing the ezcMailPop3TransportOptions class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Class containing the options for POP3 transport.
*
* The options from {@link ezcMailTransportOptions} are inherited.
*
* Example of how to use POP3 transport options:
* <code>
* $options = new ezcMailPop3TransportOptions();
* $options->ssl = true;
* $options->timeout = 3;
* $options->authenticationMethod = ezcMailPop3Transport::AUTH_APOP;
*
* $pop3 = new ezcMailPop3Transport( 'pop3.example.com', null, $options );
* </code>
*
* @property int $authenticationMethod
* Specifies the method to connect to the POP3 transport. The methods
* supported are {@link ezcMailPop3Transport::AUTH_PLAIN_TEXT} and
* {@link ezcMailPop3Transport::AUTH_APOP}.
*
* @package Mail
* @version //autogen//
*/
class ezcMailPop3TransportOptions extends ezcMailTransportOptions
{
/**
* Constructs an object with the specified values.
*
* @throws ezcBasePropertyNotFoundException
* if $options contains a property not defined
* @throws ezcBaseValueException
* if $options contains a property with a value not allowed
* @param array(string=>mixed) $options
*/
public function __construct( array $options = array() )
{
// default authentication method is PLAIN
$this->authenticationMethod = ezcMailPop3Transport::AUTH_PLAIN_TEXT;
parent::__construct( $options );
}
/**
* Sets the option $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property $name is not defined
* @throws ezcBaseValueException
* if $value is not correct for the property $name
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'authenticationMethod':
if ( !is_numeric( $value ) )
{
throw new ezcBaseValueException( $name, $value, 'int' );
}
$this->properties[$name] = (int) $value;
break;
default:
parent::__set( $name, $value );
}
}
}
?>

View file

@ -0,0 +1,123 @@
<?php
/**
* File containing the ezcMailSmtpTransportOptions class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Class containing the options for SMTP transport.
*
* The options from {@link ezcMailTransportOptions} are inherited.
*
* Example of how to use SMTP transport options:
* <code>
* $options = new ezcMailSmtpTransportOptions();
* $options->timeout = 3;
* $options->connectionType = ezcMailSmtpTransport::CONNECTION_SSL;
* $options->preferredAuthMethod = ezcMailSmtpTransport::AUTH_NTLM;
*
* $smtp = new ezcMailSmtpTransport( 'smtp.example.com', 'user', 'password', null, $options );
*
* // the options can also be set via the options property of the SMTP transport:
* $smtp->options->preferredAuthMethod = ezcMailSmtpTransport::AUTH_NTLM;
* </code>
*
* @property string $connectionType
* Specifies the protocol used to connect to the SMTP server. See the
* CONNECTION_* constants in the {@link ezcMailSmtpTransport} class.
* @property array(mixed) $connectionOptions
* Specifies additional options for the connection. Must be in this format:
* array( 'wrapper_name' => array( 'option_name' => 'value' ) ).
* @property bool $ssl
* This option belongs to {@link ezcMailTransportOptions}, but it is
* not used in SMTP.
* When trying to set this to true the connectionType option will be set to
* {@link ezcMailSmtpTransport::CONNECTION_SSL}.
* When trying to set this to false the connectionType option will be set to
* {@link ezcMailSmtpTransport::CONNECTION_PLAIN}.
* @property string $preferredAuthMethod
* Specifies which authentication method should be attempted. Default is
* null which means that that the transport should try to
* authenticate using the methods supported by the SMTP server in their
* decreasing strength order. If one method fails an exception will be
* thrown. See the AUTH_* constants in the {@link ezcMailSmtpTransport}
* class.
*
* @package Mail
* @version //autogen//
*/
class ezcMailSmtpTransportOptions extends ezcMailTransportOptions
{
/**
* Constructs an object with the specified values.
*
* @throws ezcBasePropertyNotFoundException
* if $options contains a property not defined
* @throws ezcBaseValueException
* if $options contains a property with a value not allowed
* @param array(string=>mixed) $options
*/
public function __construct( array $options = array() )
{
$this->connectionType = ezcMailSmtpTransport::CONNECTION_PLAIN; // default is plain connection
$this->connectionOptions = array(); // default is no extra connection options
$this->preferredAuthMethod = null; // default is to try the AUTH methods supported by the SMTP server
parent::__construct( $options );
}
/**
* Sets the option $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property $name is not defined
* @throws ezcBaseValueException
* if $value is not correct for the property $name
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'connectionType':
$this->properties[$name] = $value;
break;
case 'connectionOptions':
if ( !is_array( $value ) )
{
throw new ezcBaseValueException( $name, $value, 'array' );
}
$this->properties[$name] = $value;
break;
case 'ssl':
if ( !is_bool( $value ) )
{
throw new ezcBaseValueException( $name, $value, 'bool' );
}
$this->properties['connectionType'] = ( $value === true ) ? ezcMailSmtpTransport::CONNECTION_SSL : ezcMailSmtpTransport::CONNECTION_PLAIN;
break;
case 'preferredAuthMethod':
$supportedAuthMethods = ezcMailSmtpTransport::getSupportedAuthMethods();
$supportedAuthMethods[] = ezcMailSmtpTransport::AUTH_AUTO;
if ( !in_array( $value, $supportedAuthMethods ) )
{
throw new ezcBaseValueException( $name, $value, implode( ' | ', $supportedAuthMethods ) );
}
$this->properties[$name] = $value;
break;
default:
parent::__set( $name, $value );
}
}
}
?>

View file

@ -0,0 +1,78 @@
<?php
/**
* File containing the ezcMailTransportOption class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Class containing the basic options for mail transports.
*
* @property int $timeout
* Specifies the time in seconds until the connection is closed if
* there is no activity through the connection.
* @property bool $ssl
* Specifies whether to use an SSL connection or not.
*
* @package Mail
* @version //autogen//
*/
class ezcMailTransportOptions extends ezcBaseOptions
{
/**
* Constructs an object with the specified values.
*
* @throws ezcBasePropertyNotFoundException
* if $options contains a property not defined
* @throws ezcBaseValueException
* if $options contains a property with a value not allowed
* @param array(string=>mixed) $options
*/
public function __construct( array $options = array() )
{
$this->timeout = 5; // default value for timeout is 5 seconds
$this->ssl = false; // default value for ssl is false
parent::__construct( $options );
}
/**
* Sets the option $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property $name is not defined
* @throws ezcBaseValueException
* if $value is not correct for the property $name
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'timeout':
if ( !is_numeric( $value ) || ( $value < 1 ) )
{
throw new ezcBaseValueException( $name, $value, 'int >= 1' );
}
$this->properties[$name] = (int) $value;
break;
case 'ssl':
if ( !is_bool( $value ) )
{
throw new ezcBaseValueException( $name, $value, 'bool' );
}
$this->properties[$name] = $value;
break;
default:
throw new ezcBasePropertyNotFoundException( $name );
}
}
}
?>

View file

@ -0,0 +1,129 @@
<?php
/**
* File containing the ezcMailHeaderHolder class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Holds the headers of a mail during parsing and allows case insensitive lookup
* but case sensitive storage.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailHeadersHolder implements ArrayAccess
{
/**
* Holds the mapping between the case insensitive key and the real key.
*
* Format: array(lowerCaseKey, mixedCaseKey)
*
* @var array(string=>string)
*/
private $lookup = array();
/**
* Holds the normal associative array between keys in correct case and values.
*
* Format: array(mixedCaseKey, value)
*
* @var array(string=>string)
*/
private $map = array();
/**
* Constructs a new case insensitive associtive array formed around the array
* $map with mixed case keys.
*
* @param array(string=>string) $map
*/
public function __construct( array $map = array() )
{
$this->map = $map;
foreach ( $map as $key => $value )
{
$this->lookup[strtolower( $key )] = $key;
}
}
/**
* Returns true if the $key exists in the array.
*
* @param string $key
* @return bool
*/
public function offsetExists( $key )
{
return array_key_exists( strtolower( $key ), $this->lookup );
}
/**
* Returns the value recognized with $key.
*
* @param string $key
* @return mixed
*/
public function offsetGet( $key )
{
$key = strtolower( $key );
if ( !array_key_exists( $key, $this->lookup ) )
{
return null;
}
return $this->map[$this->lookup[$key]];
}
/**
* Sets the offset $key to the value $value.
*
* If it is a new entry the case in $key will be stored. If the $key exists already
* using a case insensitive lookup the new spelling will be discarded.
*
* @param string $key
* @param mixed $value
*/
public function offsetSet( $key, $value )
{
$lowerKey = strtolower( $key );
if ( !array_key_exists( $lowerKey, $this->lookup ) )
{
$this->map[$key] = $value;
$this->lookup[$lowerKey] = $key;
}
else // use old case
{
$this->map[$this->lookup[$lowerKey]] = $value;
}
}
/**
* Unsets the key $key.
*
* @param string $key
*/
public function offsetUnset( $key )
{
$key = strtolower( $key );
if ( array_key_exists( $key, $this->lookup ) )
{
unset( $this->map[$this->lookup[$key]] );
unset( $this->lookup[$key] );
}
}
/**
* Returns a copy of the associative array with the case of the keys preserved.
*
* @return array(string=>string)
*/
public function getCaseSensitiveArray()
{
return $this->map;
}
}
?>

View file

@ -0,0 +1,49 @@
<?php
/**
* File containing the ezcMailParserSet interface
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Interface common to all parser sets.
*
* A parser set provides a simple interface to fetch mail data line by
* line from a set of mail.
*
* @package Mail
* @version //autogen//
*/
interface ezcMailParserSet
{
/**
* Returns one line of data from the current mail in the set
* including the ending linebreak.
*
* Null is returned if there is no current mail in the set or
* the end of the mail is reached,
*
* @return string
*/
public function getNextLine();
/**
* Moves the set to the next mail and returns true upon success.
*
* False is returned if there are no more mail in the set.
*
* @return bool
*/
public function nextMail();
/**
* Returns true if mail data is available for parsing.
*
* @return bool
*/
public function hasData();
}
?>

View file

@ -0,0 +1,265 @@
<?php
/**
* File containing the ezcMailPartParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Base class for all parser parts.
*
* Parse process
* 1. Figure out the headers of the next part.
* 2. Based on the headers, create the parser for the bodyPart corresponding to
* the headers.
* 3. Parse the body line by line. In the case of a multipart or a digest recursively
* start this process. Note that in the case of RFC822 messages the body contains
* headers.
* 4. call finish() on the partParser and retrieve the ezcMailPart
*
* Each parser part gets the header for that part through the constructor
* and is responsible for parsing the body of that part.
* Parsing of the body is done on a push basis trough the parseBody() method
* which is called repeatedly by the parent part for each line in the message.
*
* When there are no more lines the parent part will call finish() and the mail
* part corresponding to the part you are parsing should be returned.
*
* @todo case on headers
* @package Mail
* @version //autogen//
* @access private
*/
abstract class ezcMailPartParser
{
/**
* Mail headers which can appear maximum one time in a mail message,
* as defined by RFC 2822.
*
* @var array(string)
*/
protected static $uniqueHeaders = array( 'bcc', 'cc', 'content-type',
'content-disposition', 'from',
'content-transfer-encoding',
'return-path',
'in-reply-to', 'references',
'message-id', 'date', 'reply-to',
'sender', 'subject', 'sender', 'to' );
/**
* The default is to parse text attachments into ezcMailTextPart objects.
*
* Setting this to true before calling the parser will parse text attachments
* into ezcMailFile objects. Use the parser options for this:
*
* <code>
* $parser = new ezcMailParser();
* $parser->options->parseTextAttachmentsAsFiles = true;
* // call $parser->parseMail( $set );
* </code>
*
* @var bool
*/
public static $parseTextAttachmentsAsFiles = false;
/**
* The name of the last header parsed.
*
* This variable is used when glueing together multi-line headers.
*
* @var string
*/
private $lastParsedHeader = null;
/**
* Parse the body of a message line by line.
*
* This method is called by the parent part on a push basis. When there
* are no more lines the parent part will call finish() to retrieve the
* mailPart.
*
* @param string $line
*/
abstract public function parseBody( $line );
/**
* Return the result of the parsed part.
*
* This method is called when all the lines of this part have been parsed.
*
* @return ezcMailPart
*/
abstract public function finish();
/**
* Returns a part parser corresponding to the given $headers.
*
* @throws ezcBaseFileNotFoundException
* if a neccessary temporary file could not be openened.
* @param ezcMailHeadersHolder $headers
* @return ezcMailPartParser
*/
static public function createPartParserForHeaders( ezcMailHeadersHolder $headers )
{
// default as specified by RFC2045 - #5.2
$mainType = 'text';
$subType = 'plain';
// parse the Content-Type header
if ( isset( $headers['Content-Type'] ) )
{
$matches = array();
// matches "type/subtype; blahblahblah"
preg_match_all( '/^(\S+)\/([^;]+)/',
$headers['Content-Type'], $matches, PREG_SET_ORDER );
if ( count( $matches ) > 0 )
{
$mainType = strtolower( $matches[0][1] );
$subType = strtolower( $matches[0][2] );
}
}
$bodyParser = null;
// create the correct type parser for this the detected type of part
switch ( $mainType )
{
/* RFC 2045 defined types */
case 'image':
case 'audio':
case 'video':
case 'application':
$bodyParser = new ezcMailFileParser( $mainType, $subType, $headers );
break;
case 'message':
switch ( $subType )
{
case "rfc822":
$bodyParser = new ezcMailRfc822DigestParser( $headers );
break;
case "delivery-status":
$bodyParser = new ezcMailDeliveryStatusParser( $headers );
break;
default:
$bodyParser = new ezcMailFileParser( $mainType, $subType, $headers );
break;
}
break;
case 'text':
// UNASSESSED: Based on diffing civi's packages with upstream 1.7beta1, this appears
// to be a local change, but I haven't found any history for why.
if ( (ezcMailPartParser::$parseTextAttachmentsAsFiles === true) &&
(preg_match('/\s*filename="?([^;"]*);?/i', $headers['Content-Disposition']) ||
preg_match( '/\s*name="?([^;"]*);?/i' , $headers['Content-Type']) ) )
{
$bodyParser = new ezcMailFileParser( $mainType, $subType, $headers );
}
else
{
$bodyParser = new ezcMailTextParser( $subType, $headers );
}
break;
case 'multipart':
switch ( $subType )
{
case 'mixed':
$bodyParser = new ezcMailMultipartMixedParser( $headers );
break;
case 'alternative':
$bodyParser = new ezcMailMultipartAlternativeParser( $headers );
break;
case 'related':
$bodyParser = new ezcMailMultipartRelatedParser( $headers );
break;
case 'digest':
$bodyParser = new ezcMailMultipartDigestParser( $headers );
break;
case 'report':
$bodyParser = new ezcMailMultipartReportParser( $headers );
break;
default:
$bodyParser = new ezcMailMultipartMixedParser( $headers );
break;
}
break;
/* extensions */
default:
// we treat the body as binary if no main content type is set
// or if it is unknown
$bodyParser = new ezcMailFileParser( $mainType, $subType, $headers );
break;
}
return $bodyParser;
}
/**
* Parses the header given by $line and adds to $headers.
*
* This method is usually used to parse the headers for a subpart. The
* only exception is RFC822 parts since you know the type in advance.
*
* @todo deal with headers that are listed several times
* @param string $line
* @param ezcMailHeadersHolder $headers
*/
protected function parseHeader( $line, ezcMailHeadersHolder $headers )
{
$matches = array();
preg_match_all( "/^([\w-_]*):\s?(.*)/", $line, $matches, PREG_SET_ORDER );
if ( count( $matches ) > 0 )
{
if ( !in_array( strtolower( $matches[0][1] ), self::$uniqueHeaders ) )
{
$arr = $headers[$matches[0][1]];
$arr[0][] = str_replace( "\t", " ", trim( $matches[0][2] ) );
$headers[$matches[0][1]] = $arr;
}
else
{
$headers[$matches[0][1]] = str_replace( "\t", " ", trim( $matches[0][2] ) );
}
$this->lastParsedHeader = $matches[0][1];
}
else if ( $this->lastParsedHeader !== null ) // take care of folding
{
if ( !in_array( strtolower( $this->lastParsedHeader ), self::$uniqueHeaders ) )
{
$arr = $headers[$this->lastParsedHeader];
$arr[0][count( $arr[0] ) - 1] .= str_replace( "\t", " ", $line );
$headers[$this->lastParsedHeader] = $arr;
}
else
{
$headers[$this->lastParsedHeader] .= str_replace( "\t", " ", $line );
}
}
// else -invalid syntax, this should never happen.
}
/**
* Scans through $headers and sets any specific header properties on $part.
*
* Currently we only have Content-Disposition on the ezcMailPart level.
* All parser parts must call this method once.
*
* @param ezcMailHeadersHolder $headers
* @param ezcMailPart $part
*/
static public function parsePartHeaders( ezcMailHeadersHolder $headers, ezcMailPart $part )
{
if ( isset( $headers['Content-Disposition'] ) )
{
$part->contentDisposition = ezcMailRfc2231Implementation::parseContentDisposition( $headers['Content-Disposition'] );
}
}
}
?>

View file

@ -0,0 +1,283 @@
<?php
/**
* File containing the ezcMailParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses a mail in RFC822 format to an ezcMail structure.
*
* By default an object of class {@link ezcMail} is returned by the parser. If
* you want to use your own mail class (which extends {@link ezcMail}),
* use {@link ezcMailParserOptions}. Example:
*
* <code>
* $options = new ezcMailParserOptions();
* $options->mailClass = 'myCustomMailClass'; // extends ezcMail
*
* $parser = new ezcMailParser( $options );
* </code>
*
* Another way to do this is:
* <code>
* $parser = new ezcMailParser();
* $parser->options->mailClass = 'myCustomMailClass'; // extends ezcMail
* </code>
*
* File attachments will be written to disk in a temporary directory.
* This temporary directory and the file attachment will be removed
* when PHP ends execution. If you want to keep the file you should move it
* to another directory.
*
* By default objects of class {@link ezcMailFile} are created to handle file
* attachments. If you want to use your own file class (which extends
* {@link ezcMailFile}), use {@link ezcMailParserOptions}. Example:
*
* <code>
* $options = new ezcMailParserOptions();
* $options->fileClass = 'myCustomFileClass'; // extends ezcMailFile
*
* $parser = new ezcMailParser( $options );
* </code>
*
* Another way to do this is:
* <code>
* $parser = new ezcMailParser();
* $parser->options->fileClass = 'myCustomFileClass'; // extends ezcMailFile
* </code>
*
* By default objects of class {@link ezcMailTextPart} are created for text
* attachments. If you want to use ezcMailFile objects instead, use
* {@link ezcMailParserOptions}. Example:
*
* <code>
* $options = new ezcMailParserOptions();
* $options->parseTextAttachmentsAsFiles = true;
*
* $parser = new ezcMailParser( $options );
* </code>
*
* Another way to do this is:
* <code>
* $parser = new ezcMailParser();
* $parser->options->parseTextAttachmentsAsFiles = true;
* </code>
*
* @property ezcMailParserOptions $options
* Holds the options you can set to the mail parser.
*
* @package Mail
* @version //autogen//
* @mainclass
*/
class ezcMailParser
{
/**
* Holds the parser of the current mail.
*
* @var ezcMailPartParser
*/
private $partParser = null;
/**
* Holds the directory where parsed mail should store temporary files.
*
* @var string
*/
private static $tmpDir = null;
/**
* Holds options you can be set to the mail parser.
*
* @var ezcMailParserOptions
*/
private $options;
/**
* Constructs a new mail parser.
*
* For options you can set to the mail parser see {@link ezcMailParserOptions}.
*
* @throws ezcBasePropertyNotFoundException
* if $options contains a property not defined
* @throws ezcBaseValueException
* if $options contains a property with a value not allowed
* @param ezcMailParserOptions|array(string=>mixed) $options
*/
public function __construct( $options = array() )
{
if ( $options instanceof ezcMailParserOptions )
{
$this->options = $options;
}
else if ( is_array( $options ) )
{
$this->options = new ezcMailParserOptions( $options );
}
else
{
throw new ezcBaseValueException( "options", $options, "ezcMailParserOptions|array" );
}
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property $name does not exist
* @throws ezcBaseValueException
* if $value is not accepted for the property $name
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'options':
if ( !( $value instanceof ezcMailParserOptions ) )
{
throw new ezcBaseValueException( 'options', $value, 'instanceof ezcMailParserOptions' );
}
$this->options = $value;
break;
default:
throw new ezcBasePropertyNotFoundException( $name );
}
}
/**
* Returns the value of the property $name.
*
* @throws ezcBasePropertyNotFoundException
* if the property $name does not exist
* @param string $name
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'options':
return $this->options;
default:
throw new ezcBasePropertyNotFoundException( $name );
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'options':
return true;
default:
return false;
}
}
/**
* Returns an array of ezcMail objects parsed from the mail set $set.
*
* You can optionally use ezcMailParserOptions to provide an alternate class
* name which will be instantiated instead of ezcMail, if you need to extend
* ezcMail.
*
* Example:
* <code>
* $options = new ezcMailParserOptions();
* $options->mailClass = 'MyMailClass';
*
* $parser = new ezcMailParser( $options );
* // if you want to use MyMailClass which extends ezcMail
* </code>
*
* @apichange Remove second parameter
*
* @throws ezcBaseFileNotFoundException
* if a neccessary temporary file could not be openened.
* @param ezcMailParserSet $set
* @param string $class Deprecated. Use $mailClass in ezcMailParserOptions class instead.
* @return array(ezcMail)
*/
public function parseMail( ezcMailParserSet $set, $class = null )
{
$mail = array();
if ( !$set->hasData() )
{
return $mail;
}
if ( $class === null )
{
$class = $this->options->mailClass;
}
do
{
$this->partParser = new ezcMailRfc822Parser();
$data = "";
$size = 0;
while ( ( $data = $set->getNextLine() ) !== null )
{
$this->partParser->parseBody( $data );
$size += strlen( $data );
}
$part = $this->partParser->finish( $class );
$part->size = $size;
$mail[] = $part;
} while ( $set->nextMail() );
return $mail;
}
/**
* Sets the temporary directory.
*
* The temporary directory must be writeable by PHP. It will be used to store
* file attachments.
*
* @todo throw if the directory is not writeable.
* @param string $dir
*/
public static function setTmpDir( $dir )
{
self::$tmpDir = $dir;
}
/**
* Returns the temporary directory.
*
* Uses the PHP 5.2.1 function sys_get_temp_dir().
*
* Note that the directory name returned will have a "slash" at the end
* ("/" for Linux and "\" for Windows).
*
* @return string
*/
public static function getTmpDir()
{
if ( self::$tmpDir === null )
{
self::$tmpDir = sys_get_temp_dir();
if ( substr( self::$tmpDir, strlen( self::$tmpDir ) - 1 ) !== DIRECTORY_SEPARATOR )
{
self::$tmpDir = self::$tmpDir . DIRECTORY_SEPARATOR;
}
}
return self::$tmpDir;
}
}
?>

View file

@ -0,0 +1,115 @@
<?php
/**
* File containing the ezcMailDeliveryStatusParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses mail parts of type "delivery-status".
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailDeliveryStatusParser extends ezcMailPartParser
{
/**
* This mail part will be returned by the method finish().
*
* @var ezcMailDeliveryStatus
*/
private $part = null;
/**
* The current section of the parsing of delivery-status headers.
*
* 0 = the per-message section
* 1, ... = the per-recipient section
*
* @var int
*/
private $section;
/**
* Holds the size of the mail part.
*
* @var int
*/
private $size;
/**
* Constructs a new ezcMailDeliveryStatusParser with additional headers $headers.
*
* @param ezcMailHeadersHolder $headers
*/
public function __construct( ezcMailHeadersHolder $headers )
{
$this->headers = $headers;
$this->section = 0;
$this->part = new ezcMailDeliveryStatus();
$this->size = 0;
}
/**
* Parses each line of the mail part.
*
* @param string $line
*/
public function parseBody( $line )
{
$this->parseHeader( $line, $this->headers );
$this->size += strlen( $line );
}
/**
* Parses the header given by $line.
*
* @param string $line
* @param ezcMailHeadersHolder $headers
*/
protected function parseHeader( $line, ezcMailHeadersHolder $headers )
{
$matches = array();
preg_match_all( "/^([\w-_]*):\s?(.*)/", $line, $matches, PREG_SET_ORDER );
if ( count( $matches ) > 0 )
{
$this->lastParsedHeader = $matches[0][1];
$this->headerValue = trim( $matches[0][2] );
}
else if ( isset( $this->lastParsedHeader ) && $this->lastParsedHeader !== null ) // take care of folding
{
$this->headerValue .= $line;
}
if ( strlen( trim( $line ) ) == 0 )
{
$this->section++;
$this->part->createRecipient();
return;
}
if ( $this->section == 0 )
{
$this->part->message[$this->lastParsedHeader] = $this->headerValue;
}
else
{
$this->part->recipients[$this->section - 1][$this->lastParsedHeader] = $this->headerValue;
}
}
/**
* Returns the ezcMailDeliveryStatus part corresponding to the parsed message.
*
* @return ezcMailDeliveryStatus
*/
public function finish()
{
unset( $this->part->recipients[$this->section - 1] ); // because one extra recipient is created in parseHeader()
$this->part->size = $this->size;
return $this->part;
}
}
?>

View file

@ -0,0 +1,309 @@
<?php
/**
* File containing the ezcMailFileParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses application/image/video and audio parts.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailFileParser extends ezcMailPartParser
{
/**
* Default class to handle file attachments when parsing mails
* is ezcMailFile.
*
* Change this to your own file class with:
* <code>
* $parser = new ezcMailParser();
* $parser->options->fileClass = 'myCustomFileClass';
* // call $parser->parseMail( $set );
* </code>
*
* where myCustomFileClass extends ezcMailFile.
*
* @var string
*/
public static $fileClass = 'ezcMailFile';
/**
* Holds the headers for this part.
*
* @var ezcMailHeadersHolder
*/
private $headers = null;
/**
* Holds the maintype of the parsed part.
*
* @var string
*/
private $mainType = null;
/**
* Holds the subtype of the parsed part.
*
* @var string
*/
private $subType = null;
/**
* Holds the filepointer to the attachment.
*
* @var resource
*/
private $fp = null;
/**
* Holds the full path and filename of the file to save to.
*
* @var string
*/
private $fileName = null;
/**
* Static counter used to generate unique directory names.
*
* @var int
*/
private static $counter = 1;
/**
* Holds if data has been written to the output file or not.
*
* This is used for delayed filter adding neccessary for quoted-printable.
*
* @var bool
*/
private $dataWritten = false;
/**
* Constructs a new ezcMailFileParser with maintype $mainType subtype $subType
* and headers $headers.
*
* @throws ezcBaseFileNotFoundException
* if the file attachment file could not be openened.
* @param string $mainType
* @param string $subType
* @param ezcMailHeadersHolder $headers
*/
public function __construct( $mainType, $subType, ezcMailHeadersHolder $headers )
{
$this->mainType = $mainType;
$this->subType = $subType;
$this->headers = $headers;
// figure out the base filename
// search Content-Disposition first as specified by RFC 2183
$matches = array();
if ( preg_match( '/\s*filename="?([^;"]*);?/i',
$this->headers['Content-Disposition'], $matches ) )
{
$fileName = trim( $matches[1], '"' );
}
// fallback to the name parameter in Content-Type as specified by RFC 2046 4.5.1
else if ( preg_match( '/\s*name="?([^;"]*);?/i',
$this->headers['Content-Type'], $matches ) )
{
$fileName = trim( $matches[1], '"' );
}
else // default
{
$fileName = "filename";
}
// clean file name (replace unsafe characters with underscores)
$fileName = strtr( $fileName, "/\\\0\"|?*<:;>+[]", '______________' );
$this->fp = $this->openFile( $fileName ); // propagate exception
}
/**
* Returns the filepointer of the opened file $fileName in a unique directory..
*
* This method will create a new unique folder in the temporary directory specified in ezcMailParser.
* The fileName property of this class will be set to the location of the new file.
*
* @throws ezcBaseFileNotFoundException
* if the file could not be opened.
* @param string $fileName
* @return resource
*/
private function openFile( $fileName )
{
// The filename is now relative, we need to extend it with the absolute path.
// To provide uniqueness we put the file in a directory based on processID and rand.
$dirName = ezcMailParser::getTmpDir() . getmypid() . '-' . self::$counter++ . '/';
if ( !is_dir( $dirName ) )
{
mkdir( $dirName, 0700 );
}
// remove the directory and the file when PHP shuts down
ezcMailParserShutdownHandler::registerForRemoval( $dirName );
$this->fileName = $dirName . $fileName;
$fp = fopen( $this->fileName, 'w' );
if ( $this->fp === false )
{
throw new ezcBaseFileNotFoundException( $this->fileName );
}
return $fp;
}
/**
* Destructs the parser object.
*
* Closes and removes any open file.
*/
public function __destruct()
{
// finish() was not called. The mail is completely broken.
// we will clean up the mess
if ( $this->fp !== null )
{
fclose( $this->fp );
$this->fp = null;
if ( $this->fileName !== null && file_exists( $this->fileName ) )
{
unlink( $this->fileName );
}
}
}
/**
* Sets the correct stream filters for the attachment.
*
* $line should contain one line of data that should be written to file.
* It is used to correctly determine the type of linebreak used in the mail.
*
* @param string $line
*/
private function appendStreamFilters( $line )
{
// append the correct decoding filter
switch ( strtolower( $this->headers['Content-Transfer-Encoding'] ) )
{
case 'base64':
stream_filter_append( $this->fp, 'convert.base64-decode' );
break;
case 'quoted-printable':
// fetch the type of linebreak
preg_match( "/(\r\n|\r|\n)$/", $line, $matches );
$lb = count( $matches ) > 0 ? $matches[0] : ezcMailTools::lineBreak();
$param = array( 'line-break-chars' => $lb );
stream_filter_append( $this->fp, 'convert.quoted-printable-decode',
STREAM_FILTER_WRITE, $param );
break;
case '7bit':
case '8bit':
// do nothing here, file is already just binary
break;
default:
// 7bit default
break;
}
}
/**
* Parse the body of a message line by line.
*
* This method is called by the parent part on a push basis. When there
* are no more lines the parent part will call finish() to retrieve the
* mailPart.
*
* The file will be decoded and saved to the given temporary directory within
* a directory based on the process ID and the time.
*
* @param string $line
*/
public function parseBody( $line )
{
if ( $line !== '' )
{
if ( $this->dataWritten === false )
{
$this->appendStreamFilters( $line );
$this->dataWritten = true;
}
fwrite( $this->fp, $line );
}
}
/**
* Return the result of the parsed file part.
*
* This method is called automatically by the parent part.
*
* @return ezcMailFile
*/
public function finish()
{
fclose( $this->fp );
$this->fp = null;
// FIXME: DIRTY PGP HACK
// When we have PGP support these lines should be removed. They are here now to hide
// PGP parts since they will show up as file attachments if not.
if ( $this->mainType == "application" &&
( $this->subType == 'pgp-signature'
|| $this->subType == 'pgp-keys'
|| $this->subType == 'pgp-encrypted' ) )
{
return null;
}
// END DIRTY PGP HACK
$filePart = new self::$fileClass( $this->fileName );
// set content type
$filePart->setHeaders( $this->headers->getCaseSensitiveArray() );
ezcMailPartParser::parsePartHeaders( $this->headers, $filePart );
switch ( strtolower( $this->mainType ) )
{
case 'image':
$filePart->contentType = ezcMailFile::CONTENT_TYPE_IMAGE;
break;
case 'audio':
$filePart->contentType = ezcMailFile::CONTENT_TYPE_AUDIO;
break;
case 'video':
$filePart->contentType = ezcMailFile::CONTENT_TYPE_VIDEO;
break;
case 'application':
$filePart->contentType = ezcMailFile::CONTENT_TYPE_APPLICATION;
break;
}
// set mime type
$filePart->mimeType = $this->subType;
// set inline disposition mode if set.
$matches = array();
if ( preg_match( '/^\s*inline;?/i',
$this->headers['Content-Disposition'], $matches ) )
{
$filePart->dispositionType = ezcMailFile::DISPLAY_INLINE;
}
if ( preg_match( '/^\s*attachment;?/i',
$this->headers['Content-Disposition'], $matches ) )
{
$filePart->dispositionType = ezcMailFile::DISPLAY_ATTACHMENT;
}
$filePart->size = filesize( $this->fileName );
return $filePart;
}
}
?>

View file

@ -0,0 +1,68 @@
<?php
/**
* File containing the ezcMailMultipartAlternativeParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses multipart/mixed mail parts.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailMultipartAlternativeParser extends ezcMailMultipartParser
{
/**
* Holds the ezcMailMultipartAlternative part corresponding to the data parsed with this parser.
*
* @var ezcMailMultipartAlternative
*/
private $part = null;
/**
* Constructs a new ezcMailMultipartAlternativeParser.
*
* @param ezcMailHeadersHolder $headers
*/
public function __construct( ezcMailHeadersHolder $headers )
{
parent::__construct( $headers );
$this->part = new ezcMailMultipartAlternative();
}
/**
* Adds the part $part to the list of multipart messages.
*
* This method is called automatically by ezcMailMultipartParser
* each time a part is parsed.
*
* @param ezcMailPart $part
*/
public function partDone( ezcMailPart $part )
{
$this->part->appendPart( $part );
}
/**
* Returns the parts parsed for this multipart.
*
* @return ezcMailMultipartAlternative
*/
public function finishMultipart()
{
$size = 0;
foreach ( $this->part->getParts() as $part )
{
$size += $part->size;
}
$this->part->size = $size;
return $this->part;
}
}
?>

View file

@ -0,0 +1,68 @@
<?php
/**
* File containing the ezcMailMultipartDigestParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses multipart/digest mail parts.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailMultipartDigestParser extends ezcMailMultipartParser
{
/**
* Holds the ezcMailMultipartDigest part corresponding to the data parsed with this parser.
*
* @var ezcMailMultipartDigest
*/
private $part = null;
/**
* Constructs a new ezcMailMultipartDigestParser.
*
* @param ezcMailHeadersHolder $headers
*/
public function __construct( ezcMailHeadersHolder $headers )
{
parent::__construct( $headers );
$this->part = new ezcMailMultipartDigest();
}
/**
* Adds the part $part to the list of multipart messages.
*
* This method is called automatically by ezcMailMultipartParser
* each time a part is parsed.
*
* @param ezcMailPart $part
*/
public function partDone( ezcMailPart $part )
{
$this->part->appendPart( $part );
}
/**
* Returns the parts parsed for this multipart.
*
* @return ezcMailMultipartDigest
*/
public function finishMultipart()
{
$size = 0;
foreach ( $this->part->getParts() as $part )
{
$size += $part->size;
}
$this->part->size = $size;
return $this->part;
}
}
?>

View file

@ -0,0 +1,67 @@
<?php
/**
* File containing the ezcMailMultipartMixedParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses multipart/mixed mail parts.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailMultipartMixedParser extends ezcMailMultipartParser
{
/**
* Holds the ezcMailMultipartMixed part corresponding to the data parsed with this parser.
*
* @var ezcMailMultipartMixed
*/
private $part = null;
/**
* Constructs a new ezcMailMultipartMixedParser.
*
* @param ezcMailHeadersHolder $headers
*/
public function __construct( ezcMailHeadersHolder $headers )
{
parent::__construct( $headers );
$this->part = new ezcMailMultipartMixed();
}
/**
* Adds the part $part to the list of multipart messages.
*
* This method is called automatically by ezcMailMultipartParser
* each time a part is parsed.
*
* @param ezcMailPart $part
*/
public function partDone( ezcMailPart $part )
{
$this->part->appendPart( $part );
}
/**
* Returns the parts parsed for this multipart.
*
* @return ezcMailMultipartMixed
*/
public function finishMultipart()
{
$size = 0;
foreach ( $this->part->getParts() as $part )
{
$size += $part->size;
}
$this->part->size = $size;
return $this->part;
}
}
?>

View file

@ -0,0 +1,230 @@
<?php
/**
* File containing the ezcMailMultipartParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Base class for Multipart parsers.
*
* @package Mail
* @version //autogen//
* @access private
*/
abstract class ezcMailMultipartParser extends ezcMailPartParser
{
/**
* The boundary separator string.
*
* @var string
*/
private $boundary = null;
/**
* The headers for the multipart.
*
* @var ezcMailHeadersHolder
*/
protected $headers = null;
/**
* The headers for the current subpart.
*
* @var ezcMailHeadersHolder
*/
private $currentPartHeaders = null;
/**
* The current part.
*
* @var ezcMailPartParser
*/
private $currentPartParser = null;
/**
* This state is used prior to hitting the first part.
*/
const PARSE_STATE_PRE_FIRST = 1;
/**
* This state is used when the parser is parsing headers.
*/
const PARSE_STATE_HEADERS = 2;
/**
* This state is used when the parser is parsing the body.
*/
const PARSE_STATE_BODY = 3;
/**
* This state is set after the last of the parts is closed.
*/
const PARSE_STATE_POST_LAST = 4;
/**
* Stores the state of the parser.
*
* @var int
*/
private $parserState = self::PARSE_STATE_PRE_FIRST;
/**
* Constructs a new Multipart parser.
*
* @param ezcMailHeadersHolder $headers
*/
public function __construct( ezcMailHeadersHolder $headers )
{
$this->headers = $headers;
// get the boundary
preg_match( '/\s*boundary="?([^;"]*);?/i',
$this->headers['Content-Type'],
$parameters );
if ( count( $parameters ) > 0 )
{
$this->boundary = trim( $parameters[1], '"' );
}
else
{
// no boundary?!? Houston, we have a problem.
// todo: try to detect the boundary by scanning for --lines
}
}
/**
* Parses a multipart body.
*
* @throws ezcBaseFileNotFoundException
* if a neccessary temporary file could not be opened.
* @param string $origLine
*/
public function parseBody( $origLine )
{
if ( $this->parserState == self::PARSE_STATE_POST_LAST )
{
return;
}
$line = rtrim( $origLine, "\r\n" );
// check if we hit any of the boundaries
$newPart = false;
$endOfMultipart = false;
if ( strlen( $line ) > 0 && $line[0] == "-" )
{
if ( strcmp( trim( $line ), '--' . $this->boundary ) === 0 )
{
$newPart = true;
}
else if ( strcmp( trim( $line ), '--' . $this->boundary . '--' ) === 0 )
{
$endOfMultipart = true;
}
}
// actions to do when starting or finishing a part
if ( $newPart || $endOfMultipart )
{
if ( $this->parserState != self::PARSE_STATE_BODY )
{
// something is b0rked, we got a new separator before getting a body
// we'll skip this part and continue to the next
$this->currentPartParser = null;
$this->currentPartHeaders = new ezcMailHeadersHolder();
$this->parserState = $newPart ? self::PARSE_STATE_HEADERS : self::PARSE_STATE_POST_LAST;
}
else
{
// complete the work on the current part if there was any
if ( $this->currentPartParser !== null )
{
$part = $this->currentPartParser->finish();
if ( $part !== null ) // parsing failed
{
$this->partDone( $part );
}
}
// prepare for a new part if any
$this->currentPartParser = null;
$this->parserState =self::PARSE_STATE_POST_LAST;
if ( $newPart )
{
$this->parserState = self::PARSE_STATE_HEADERS;
$this->currentPartHeaders = new ezcMailHeadersHolder();
}
}
}
// normal data, pass to headers or current body
else
{
if ( $this->parserState == self::PARSE_STATE_HEADERS && $line == '' )
{
$this->currentPartParser = self::createPartParserForHeaders( $this->currentPartHeaders );
$this->parserState = self::PARSE_STATE_BODY;
}
else if ( $this->parserState == self::PARSE_STATE_HEADERS )
{
$this->parseHeader( $line, $this->currentPartHeaders );
}
else if ( $this->parserState == self::PARSE_STATE_BODY )
{
if ( $this->currentPartParser ) // we may have none if the part type was unknown
{
// send body data to the part
$this->currentPartParser->parseBody( $origLine );
}
}
// we are done parsing the multipart, ignore anything else pushed to us.
}
}
/**
* Completes the parsing of the multipart and returns the corresponding part.
*
* This method should not be overriden. Use finishMultipart() instead.
*
* @return ezcMailMultipart
*/
public function finish()
{
if ( $this->parserState != self::PARSE_STATE_POST_LAST )
{
// this should never happen
// let's give the last parser a chance to clean up after himself
if ( $this->currentPartParser !== null )
{
$part = $this->currentPartParser->finish();
$this->partDone( $part );
$this->currentPartParser = null;
}
}
$multipart = $this->finishMultipart();
ezcMailPartParser::parsePartHeaders( $this->headers, $multipart );
$multipart->boundary = $this->boundary;
return $multipart;
}
/**
* This function will be called every time a part has been parsed.
*
* Implementors should put the part into the correct multitype part.
* @param ezcMailPart $part
*/
abstract public function partDone( ezcMailPart $part );
/**
* Returns the multipart part corresponding to the parsed object.
*
* This method is called by finish() when all parts have been parsed.
*
* @return ezcMailMultipart
*/
abstract public function finishMultipart();
}
?>

View file

@ -0,0 +1,78 @@
<?php
/**
* File containing the ezcMailMultipartRelatedParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses multipart/related mail parts.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailMultipartRelatedParser extends ezcMailMultipartParser
{
/**
* Holds the ezcMailMultipartRelated part corresponding to the data parsed with this parser.
*
* @var ezcMailMultipartRelated
*/
private $part = null;
/**
* Constructs a new ezcMailMultipartRelatedParser.
*
* @param ezcMailHeadersHolder $headers
*/
public function __construct( ezcMailHeadersHolder $headers )
{
parent::__construct( $headers );
$this->part = new ezcMailMultipartRelated();
}
/**
* Adds the part $part to the list of multipart messages.
*
* This method is called automatically by ezcMailMultipartParser
* each time a part is parsed.
*
* @param ezcMailPart $part
*/
public function partDone( ezcMailPart $part )
{
// TODO: support Content-Type: start= as specified by RFC 2387
if ( !$this->part->getMainPart() )
{
$this->part->setMainPart( $part );
return;
}
$this->part->addRelatedPart( $part );
}
/**
* Returns the parts parsed for this multipart.
*
* @return ezcMailMultipartRelated
*/
public function finishMultipart()
{
$size = 0;
if ( $this->part->getMainPart() )
{
$size = $this->part->getMainPart()->size;
}
foreach ( $this->part->getRelatedParts() as $part )
{
$size += $part->size;
}
$this->part->size = $size;
return $this->part;
}
}
?>

View file

@ -0,0 +1,94 @@
<?php
/**
* File containing the ezcMailMultipartReportParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses multipart/report mail parts.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailMultipartReportParser extends ezcMailMultipartParser
{
/**
* Holds the ezcMailMultipartReport part corresponding to the data parsed with this parser.
*
* @var ezcMailMultipartReport
*/
private $report;
/**
* Holds the mail parts which will be part of the returned multipart report.
*
* @var array(ezcMailPart)
*/
private $parts;
/**
* Constructs a new ezcMailMultipartReportParser.
*
* @param ezcMailHeadersHolder $headers
*/
public function __construct( ezcMailHeadersHolder $headers )
{
parent::__construct( $headers );
$this->report = new ezcMailMultipartReport();
$this->parts = array();
preg_match( '/\s*report-type="?([^;"]*);?/i',
$this->headers['Content-Type'],
$parameters );
if ( count( $parameters ) > 0 )
{
$this->report->reportType = trim( $parameters[1], '"' );
}
}
/**
* Adds the part $part to the list of multipart messages.
*
* This method is called automatically by ezcMailMultipartParser
* each time a part is parsed.
*
* @param ezcMailPart $part
*/
public function partDone( ezcMailPart $part )
{
$this->parts[] = $part;
}
/**
* Returns the parts parsed for this multipart.
*
* @return ezcMailMultipartReport
*/
public function finishMultipart()
{
if ( isset( $this->parts[0] ) )
{
$this->report->setReadablePart( $this->parts[0] );
}
if ( isset( $this->parts[1] ) )
{
$this->report->setMachinePart( $this->parts[1] );
}
if ( isset( $this->parts[2] ) )
{
$this->report->setOriginalPart( $this->parts[2] );
}
$size = 0;
foreach ( $this->report->getParts() as $part )
{
$size += $part->size;
}
$this->report->size = $size;
return $this->report;
}
}
?>

View file

@ -0,0 +1,82 @@
<?php
/**
* File containing the ezcMailRfc822DigestParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses RFC822 messages.
*
* Note that this class does not parse RFC822 digest messages containing of an extra header block.
* Use the RFC822DigestParser to these.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailRfc822DigestParser extends ezcMailPartParser
{
/**
* Holds the headers for this part.
*
* @var ezcMailHeadersHolder
*/
private $headers = null;
/**
* Holds the digested message parser.
*
* @var ezcMailPartParser
*/
private $mailParser = null;
/**
* Holds the size of the digest.
*
* @var int
*/
private $size;
/**
* Constructs a new digest parser with the headers $headers.
*
* @param ezcMailHeadersHolder $headers
*/
public function __construct( ezcMailHeadersHolder $headers )
{
$this->headers = $headers;
$this->mailParser = new ezcMailRfc822Parser();
$this->size = 0;
}
/**
* Parses each line of the digest body.
*
* Every line is part of the digested mail. It is sent directly to the mail parser.
*
* @param string $line
*/
public function parseBody( $line )
{
$this->mailParser->parseBody( $line );
$this->size += strlen( $line );
}
/**
* Returns a ezcMailRfc822Digest with the digested mail in it.
*
* @return ezcMailRfc822Digest
*/
public function finish()
{
$digest = new ezcMailRfc822Digest( $this->mailParser->finish() );
ezcMailPartParser::parsePartHeaders( $this->headers, $digest );
$digest->size = $this->size;
return $digest;
}
}
?>

View file

@ -0,0 +1,165 @@
<?php
/**
* File containing the ezcMailRfc822Parser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses RFC822 messages.
*
* Note that this class does not parse RFC822 digest messages containing an extra header block.
* Use the RFC822DigestParser to these.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailRfc822Parser extends ezcMailPartParser
{
/**
* Holds the headers parsed.
*
* @var ezcMailHeadersHolder
*/
private $headers = null;
/**
* This state is used when the parser is parsing headers.
*/
const PARSE_STATE_HEADERS = 1;
/**
* This state is used when the parser is parsing the body.
*/
const PARSE_STATE_BODY = 2;
/**
* Stores the state of the parser.
*
* @var int
*/
private $parserState = self::PARSE_STATE_HEADERS;
/**
* The parser of the body.
*
* This will be set after the headers have been parsed.
*
* @var ezcMailPartParser
*/
private $bodyParser = null;
/**
* Constructs a new ezcMailRfc822Parser.
*/
public function __construct()
{
$this->headers = new ezcMailHeadersHolder();
}
/**
* Parses the body of an rfc 2822 message.
*
* @throws ezcBaseFileNotFoundException
* if a neccessary temporary file could not be openened.
* @param string $origLine
*/
public function parseBody( $origLine )
{
$line = rtrim( $origLine, "\r\n" );
if ( $this->parserState == self::PARSE_STATE_HEADERS && $line == '' )
{
$this->parserState = self::PARSE_STATE_BODY;
// clean up headers for the part
// the rest of the headers should be set on the mail object.
$headers = new ezcMailHeadersHolder();
$headers['Content-Type'] = $this->headers['Content-Type'];
if ( isset( $this->headers['Content-Transfer-Encoding'] ) )
{
$headers['Content-Transfer-Encoding'] = $this->headers['Content-Transfer-Encoding'];
}
if ( isset( $this->headers['Content-Disposition'] ) )
{
$headers['Content-Disposition'] = $this->headers['Content-Disposition'];
}
// get the correct body type
$this->bodyParser = self::createPartParserForHeaders( $headers );
}
else if ( $this->parserState == self::PARSE_STATE_HEADERS )
{
$this->parseHeader( $line, $this->headers );
}
else // we are parsing headers
{
$this->bodyParser->parseBody( $origLine );
}
}
/**
* Returns an ezcMail corresponding to the parsed message.
* You can specify an alternate class using the $class parameter, if you
* extended ezcMail.
*
* @param string $class Class to instanciate instead of ezcMail.
* @return ezcMail
*/
public function finish( $class = "ezcMail" )
{
$mail = new $class();
$mail->setHeaders( $this->headers->getCaseSensitiveArray() );
ezcMailPartParser::parsePartHeaders( $this->headers, $mail );
// from
if ( isset( $this->headers['From'] ) )
{
$mail->from = ezcMailTools::parseEmailAddress( $this->headers['From'] );
}
// to
if ( isset( $this->headers['To'] ) )
{
$mail->to = ezcMailTools::parseEmailAddresses( $this->headers['To'] );
}
// cc
if ( isset( $this->headers['Cc'] ) )
{
$mail->cc = ezcMailTools::parseEmailAddresses( $this->headers['Cc'] );
}
// bcc
if ( isset( $this->headers['Bcc'] ) )
{
$mail->bcc = ezcMailTools::parseEmailAddresses( $this->headers['Bcc'] );
}
// subject
if ( isset( $this->headers['Subject'] ) )
{
$mail->subject = ezcMailTools::mimeDecode( $this->headers['Subject'] );
$mail->subjectCharset = 'utf-8';
}
// message ID
if ( isset( $this->headers['Message-Id'] ) )
{
$mail->messageID = $this->headers['Message-Id'];
}
// Return-Path
if ( isset( $this->headers['Return-Path'] ) )
{
$mail->returnPath = ezcMailTools::parseEmailAddress( $this->headers['Return-Path'] );
}
if ( $this->bodyParser !== null )
{
$mail->body = $this->bodyParser->finish();
}
return $mail;
}
}
?>

View file

@ -0,0 +1,111 @@
<?php
/**
* File containing the ezcMailTextParser class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Parses mail parts of type "text".
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailTextParser extends ezcMailPartParser
{
/**
* Stores the parsed text of this part.
*
* @var string $text
*/
private $text = null;
/**
* Holds the headers of this text part.
*
* @var ezcMailHeadersHolder
*/
private $headers = null;
/**
* Holds the subtype of the parsed part.
*
* @var string
*/
private $subType = null;
/**
* Constructs a new ezcMailTextParser of the subtype $subType and
* additional headers $headers.
*
* @param string $subType
* @param ezcMailHeadersHolder $headers
*/
public function __construct( $subType, ezcMailHeadersHolder $headers )
{
$this->subType = $subType;
$this->headers = $headers;
}
/**
* Adds each line to the body of the text part.
*
* @param string $line
*/
public function parseBody( $line )
{
$line = rtrim( $line, "\r\n" );
if ( $this->text === null )
{
$this->text = $line;
}
else
{
$this->text .= "\n" . $line;
}
}
/**
* Returns the ezcMailText part corresponding to the parsed message.
*
* @return ezcMailText
*/
public function finish()
{
$charset = "us-ascii"; // RFC 2822 default
if ( isset( $this->headers['Content-Type'] ) )
{
preg_match( '/\s*charset\s?=\s?"?([^;"\s]*);?/',
$this->headers['Content-Type'],
$parameters );
if ( count( $parameters ) > 0 )
{
$charset = strtolower( trim( $parameters[1], '"' ) );
}
}
$encoding = strtolower( $this->headers['Content-Transfer-Encoding'] );
if ( $encoding == ezcMail::QUOTED_PRINTABLE )
{
$this->text = quoted_printable_decode( $this->text );
}
else if ( $encoding == ezcMail::BASE64 )
{
$this->text = base64_decode( $this->text );
}
$this->text = ezcMailCharsetConverter::convertToUTF8( $this->text, $charset );
$part = new ezcMailText( $this->text, 'utf-8', ezcMail::EIGHT_BIT, $charset );
$part->subType = $this->subType;
$part->setHeaders( $this->headers->getCaseSensitiveArray() );
ezcMailPartParser::parsePartHeaders( $this->headers, $part );
$part->size = strlen( $this->text );
return $part;
}
}
?>

View file

@ -0,0 +1,192 @@
<?php
/**
* File containing the ezcMailRfc2231Implementation class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @access private
*/
/**
* This class parses header fields that conform to RFC2231.
*
* Headers conforming to this specification are Content-Type and Content-Disposition.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailRfc2231Implementation
{
/**
* Returns the parsed header $header according to RFC 2231.
*
* This method returns the parsed header as a structured array and is
* intended for internal usage. Use parseContentDisposition and
* parseContentType to retrieve the correct header structs directly.
*
* @param string $header
* @return array( 'argument', array( 'paramName' => array( value => string, charset => string,
* language => string ) ) );
*/
public static function parseHeader( $header )
{
$result = array();
// argument
if ( preg_match( '/^\s*([^;]*);?/i', $header, $matches ) )
{
$result[0] = $matches[1];
}
// We must go through all parameters and store this data because
// parameters can be unordered. We will store them in this buffer
// array( paramName => array( array( value => string, encoding ) ) )
$parameterBuffer = array();
// parameters
if ( preg_match_all( '/\s*(\S*?)="?([^;"]*);?/i', $header, $matches, PREG_SET_ORDER ) )
{
foreach ( $matches as $parameter )
{
// if normal parameter, simply add it
if ( !preg_match( '/([^\*]+)\*(\d+)?(\*)?/', $parameter[1], $metaData ) )
{
$result[1][$parameter[1]] = array( 'value' => $parameter[2] );
}
else // coded and/or folded
{
// metaData [1] holds the param name
// metaData [2] holds the count or is not set in case of charset only
// metaData [3] holds '*' if there is charset in addition to folding
if ( isset( $metaData[2] ) ) // we have folding
{
$parameterBuffer[$metaData[1]][$metaData[2]]['value'] = $parameter[2];
$parameterBuffer[$metaData[1]][$metaData[2]]['encoding'] =
isset( $metaData[3] ) ? true : false;;
}
else
{
$parameterBuffer[$metaData[1]][0]['value'] = $parameter[2];
$parameterBuffer[$metaData[1]][0]['encoding'] = true;
}
}
}
// whohooo... we have all the parameters nicely sorted.
// Now we must go through them all and convert them into the end result
foreach ( $parameterBuffer as $paramName => $parts )
{
// fetch language and encoding if we have it
// syntax: '[charset]'[language]'encoded_string
$language = null;
$charset = null;
if ( $parts[0]['encoding'] == true )
{
preg_match( "/(\S*)'(\S*)'(.*)/", $parts[0]['value'], $matches );
$charset = $matches[1];
$language = $matches[2];
$parts[0]['value'] = urldecode( $matches[3] ); // rewrite value: todo: decoding
$result[1][$paramName] = array( 'value' => $parts[0]['value'] );
}
$result[1][$paramName] = array( 'value' => $parts[0]['value'] );
if ( strlen( $charset ) > 0 )
{
$result[1][$paramName]['charset'] = $charset;
}
if ( strlen( $language ) > 0 )
{
$result[1][$paramName]['language'] = $language;
}
if ( count( $parts > 1 ) )
{
for ( $i = 1; $i < count( $parts ); $i++ )
{
$result[1][$paramName]['value'] .= $parts[$i]['encoding'] ?
urldecode( $parts[$i]['value'] ) : $parts[$i]['value'];
}
}
}
}
return $result;
}
/**
* Returns the a ezcMailContentDispositionHeader for the parsed $header.
*
* If $cd is provided this object will be used to fill in the blanks. This function
* will not clear out any old values in the object.
*
* @param string $header
* @param ezcMailContentDispositionHeader $cd
* @return ezcMailContentDispositionHeader
*/
public static function parseContentDisposition( $header, ezcMailContentDispositionHeader $cd = null )
{
if ( $cd === null )
{
$cd = new ezcMailContentDispositionHeader();
}
$parsedHeader = self::parseHeader( $header );
$cd->disposition = $parsedHeader[0];
if ( isset( $parsedHeader[1] ) )
{
foreach ( $parsedHeader[1] as $paramName => $data )
{
switch ( $paramName )
{
case 'filename':
$cd->fileName = $data['value'];
$cd->displayFileName = trim( $data['value'], '"' );
if ( isset( $data['charset'] ) )
{
$cd->fileNameCharSet = $data['charset'];
$cd->displayFileName = ezcMailCharsetConverter::convertToUTF8Iconv( $cd->displayFileName, $cd->fileNameCharSet );
}
// Work around for bogus email clients that think
// it's allowed to use mime-encoding for filenames.
// It isn't, see RFC 2184, and issue #13038.
else if ( preg_match( '@^=\?[^?]+\?[QqBb]\?@', $cd->displayFileName ) )
{
$cd->displayFileName = ezcMailTools::mimeDecode( $cd->displayFileName );
}
if ( isset( $data['language'] ) )
{
$cd->fileNameLanguage = $data['language'];
}
break;
case 'creation-date':
$cd->creationDate = $data['value'];
break;
case 'modification-date':
$cd->modificationDate = $data['value'];
break;
case 'read-date':
$cd->readDate = $data['value'];
break;
case 'size':
$cd->size = $data['value'];
break;
default:
$cd->additionalParameters[$paramName] = $data['value'];
if ( isset( $data['charset'] ) )
{
$cd->additionalParametersMetaData[$paramName]['charSet'] = $data['charset'];
}
if ( isset( $data['language'] ) )
{
$cd->additionalParametersMetaData[$paramName]['language'] = $data['language'];
}
break;
}
}
}
return $cd;
}
}
?>

View file

@ -0,0 +1,117 @@
<?php
/**
* File containing the ezcMailParserShutdownHandler class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcMailParserShutDownHandler removes temporary files
* and directories when PHP shuts down.
*
* Example:
* <code>
* ezcMailParserShutdownHandler::registerForRemoval( "/tmp/file.txt" );
* </code>
*
* The code above will result in file.txt being removed from the system
* (if it still exists) when PHP shuts down.
*
* @package Mail
* @version //autogen//
* @access private
*/
class ezcMailParserShutdownHandler
{
/**
* Holds if the handler is registered or not.
*
* @var boolean
*/
private static $isRegistered = false;
/**
* Holds the array of directories that are marked for removal
* when PHP shuts down.
*
* @var array(string)
*/
private static $directories = array();
/**
* Registers the directory $dir for removal when PHP shuts down.
*
* The directory and all of its contents will be removed recursively.
*
* @param string $dir
*/
public static function registerForRemoval( $dir )
{
if ( self::$isRegistered === false )
{
register_shutdown_function( array( "ezcMailParserShutdownHandler", "shutdownCallback" ) );
self::$isRegistered = true;
}
self::$directories[] = $dir;
}
/**
* Recursively deletes all registered folders and any contents of the registered
* directories.
*
* Files or directories that can't be deleted are left without warning.
*
* @return void
*/
public static function shutdownCallback()
{
foreach ( self::$directories as $directory )
{
self::remove( $directory );
}
}
/**
* Recursively removes a directory and its contents or a file.
*
* Returns true on success and false on error.
*
* @param string $itemName
* @return bool
*/
public static function remove( $itemName )
{
$returnVar = true;
if ( !is_dir( $itemName ) && file_exists( $itemName ) )
{
unlink( $itemName );
return true;
}
if ( !file_exists( $itemName ) )
{
return true;
}
$dir = dir( $itemName );
$item = $dir->read();
while ( $item !== false )
{
if ( $item != '.' && $item != '..' )
{
self::remove( $dir->path . DIRECTORY_SEPARATOR . $item );
$returnVar = false;
}
$item = $dir->read();
}
$dir->close();
$returnVar = rmdir( $itemName ) && $returnVar ? true : false; // if rmdir succeeds and everything else succeeded
return $returnVar;
}
}
?>

View file

@ -0,0 +1,178 @@
<?php
/**
* File containing the ezcMailDeliveryStatus class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Mail part used for sending delivery status message.
*
* Multipart/Report: RFC 3462 {@link http://tools.ietf.org/html/rfc3462}
* Delivery Status Notifications: RFC 3464 {@link http://tools.ietf.org/html/rfc3464}
*
* This mail part consists of only headers. The headers are organized into section.
* There is a per-message section ($message), and several per-recipient sections ($recipients).
*
* To access the headers of this part, look at the following example:
* <code>
* // $delivery is an object of type ezcMailDeliveryStatus
* $reportingMta = $delivery->message["Reporting-MTA"];
* $date = $delivery->message["Arrival-Date"];
* // get the status received from the first recipient
* $status1 = $delivery->recipients[0]["Status"];
* // get the status received from the second recipient
* $status2 = $delivery->recipients[1]["Status"];
* </code>
*
* @property ezcMailHeadersHolder $message
* Holds the per-message headers of the delivery-status message.
* @property ArrayObject(ezcMailHeadersHolder) $recipients
* Holds the recipients of the delivery-status message.
*
* @package Mail
* @version //autogen//
*/
class ezcMailDeliveryStatus extends ezcMailPart
{
/**
* Constructs a new DeliveryStatus part.
*/
public function __construct()
{
$this->message = new ezcMailHeadersHolder();
$this->recipients = new ArrayObject();
parent::__construct();
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'message':
case 'recipients':
$this->properties[$name] = $value;
break;
default:
return parent::__set( $name, $value );
break;
}
}
/**
* Returns the property $name.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist
* @param string $name
* @return mixed
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'message':
case 'recipients':
return $this->properties[$name];
break;
default:
return parent::__get( $name );
break;
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'message':
case 'recipients':
return isset( $this->properties[$name] );
default:
return parent::__isset( $name );
}
}
/**
* Returns the headers set for this part as a RFC822 compliant string.
*
* This method does not add the required two lines of space
* to separate the headers from the body of the part.
*
* @see setHeader()
* @return string
*/
public function generateHeaders()
{
$this->setHeader( "Content-Type", "message/delivery-status" );
return parent::generateHeaders();
}
/**
* Returns the generated text body of this part as a string.
*
* @return string
*/
public function generateBody()
{
$result = $this->addHeadersSection( $this->message ) . ezcMailTools::lineBreak();
for ( $i = 0; $i < count( $this->recipients ); $i++ )
{
$result .= $this->addHeadersSection( $this->recipients[$i] ) . ezcMailTools::lineBreak();
}
return $result;
}
/**
* Returns the generated text for a section of the delivery-status part.
*
* @param ezcMailHeadersHolder $headers
* @return string
*/
private function addHeadersSection( ezcMailHeadersHolder $headers )
{
$result = "";
foreach ( $headers->getCaseSensitiveArray() as $header => $value )
{
$result .= $header . ": " . $value . ezcMailTools::lineBreak();
}
return $result;
}
/**
* Adds a new recipient to this delivery-status message and returns the index
* of the last added recipient.
*
* @return int
*/
public function createRecipient()
{
$result = count( $this->recipients );
$this->recipients[$result] = new ezcMailHeadersHolder();
return $result;
}
}
?>

View file

@ -0,0 +1,235 @@
<?php
/**
* File containing the ezcMailFilePart class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Mail part for all forms of binary data.
*
* @todo MimeType recognition
*
* @property string $fileName
* The name of the file which is to be attached to the email.
* @property string $mimeType
* The mimetype of the file.
* @property string $contentType
* The content type of the file.
* Possible values are: CONTENT_TYPE_IMAGE, CONTENT_TYPE_VIDEO and
* CONTENT_TYPE_APPLICATION.
* @property string $dispositionType
* If the file should be shown inline in the mail or as an
* attachment. Possible values are: DISPLAY_ATTACHMENT and
* DISPLAY_INLINE.
* @property int $contentId
* The ID of this part. Used for internal links within an email.
* Setting this also sets the header Content-ID.
*
* @package Mail
* @version //autogen//
*/
abstract class ezcMailFilePart extends ezcMailPart
{
/**
* Image content type. Use this if the contents of the file is an image.
*/
const CONTENT_TYPE_IMAGE = "image";
/**
* Video content type. Use this if the contents of the file is a video.
*/
const CONTENT_TYPE_VIDEO = "video";
/**
* Audio content type. Use this if the contents of the file is an audio.
*/
const CONTENT_TYPE_AUDIO = "audio";
/**
* Application content type. Use this if the file non of the other
* content types match.
*/
const CONTENT_TYPE_APPLICATION = "application";
/**
* Use DISPLAY_ATTACHMENT if you want the file to be displayed as an
* attachment to the recipients of the mail.
*/
const DISPLAY_ATTACHMENT = "attachment";
/**
* Use DISPLAY_INLINE if you want the file to be displayed inline in the
* mail to the recipients.
*/
const DISPLAY_INLINE = "inline";
/**
* Constructs a new attachment with $fileName.
*
* @param string $fileName
*/
public function __construct( $fileName )
{
parent::__construct();
// initialize properties that may be touched automatically
// this is to avoid notices
$this->properties['contentType'] = null;
$this->properties['mimeType'] = null;
$this->properties['dispositionType'] = null;
$this->properties['contentId'] = null;
$this->fileName = $fileName;
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'fileName':
$this->properties['fileName'] = $value;
break;
case 'mimeType':
$this->properties['mimeType'] = $value;
break;
case 'contentType':
$this->properties['contentType'] = $value;
break;
case 'dispositionType':
$this->properties['dispositionType'] = $value;
break;
case 'contentId':
$this->properties['contentId'] = $value;
$this->setHeader( 'Content-ID', '<' . $value . '>' );
break;
default:
return parent::__set( $name, $value );
break;
}
}
/**
* Returns the value of property $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @return mixed
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'fileName':
case 'mimeType':
case 'contentType':
case 'dispositionType':
case 'contentId':
return $this->properties[$name];
break;
default:
return parent::__get( $name );
break;
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'fileName':
case 'mimeType':
case 'contentType':
case 'dispositionType':
case 'contentId':
return isset( $this->properties[$name] );
default:
return parent::__isset( $name );
}
}
/**
* Sets the Content-Type header.
*
* Based on the contentType, mimeType and fileName.
*/
private function setHeaderContentType()
{
$fileName = basename( $this->fileName );
if ( $this->contentDisposition !== null && $this->contentDisposition->fileName !== null )
{
$fileName = $this->contentDisposition->fileName;
}
$this->setHeader( 'Content-Type',
$this->contentType . '/' . $this->mimeType . '; ' . 'name="' . $fileName . '"' );
}
/**
* Sets the Content-Disposition header based on the properties $dispositionType and $fileName.
*
* Does not set the fileNameCharSet and fileNameLanguage properties of the
* Content-Disposition header. For this purpose set directly
* $this->contentDisposition with an object of class ezcMailContentDispositionHeader.
*/
private function setHeaderContentDisposition()
{
if ( !isset( $this->dispositionType ) )
{
$this->dispositionType = self::DISPLAY_ATTACHMENT;
}
if ( $this->contentDisposition == null )
{
$this->contentDisposition = new ezcMailContentDispositionHeader();
// modified for issue #14025: set the file name and disposition
// only if the contentDisposition was null (to not overwrite
// the value set by the user)
$this->contentDisposition->disposition = $this->dispositionType;
$this->contentDisposition->fileName = basename( $this->fileName );
}
}
/**
* Override of the generate() method from ezcMailPart. Used to set headers before
* generating the part.
*
* @return string
*/
public function generate()
{
$this->setHeaderContentType();
$this->setHeader( 'Content-Transfer-Encoding', 'base64' );
$this->setHeaderContentDisposition();
return parent::generate();
}
}
?>

View file

@ -0,0 +1,140 @@
<?php
/**
* File containing the ezcMailFile class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Mail part for binary data from the file system.
*
* @package Mail
* @version //autogen//
*/
class ezcMailFile extends ezcMailFilePart
{
/**
* Constructs a new attachment with $fileName.
*
* If the $mimeType and $contentType are not specified they are extracted
* with the fileinfo extension if it is available, otherwise they are set
* to application/octet-stream.
*
* @param string $fileName
* @param string $contentType
* @param string $mimeType
*/
public function __construct( $fileName, $contentType = null, $mimeType = null )
{
parent::__construct( $fileName );
if ( $contentType != null && $mimeType != null )
{
$this->contentType = $contentType;
$this->mimeType = $mimeType;
}
elseif ( ezcBaseFeatures::hasExtensionSupport( 'fileinfo' ) )
{
// get mime and content type
$fileInfo = finfo_open( FILEINFO_MIME );
$mimeParts = finfo_file( $fileInfo, $fileName );
if ( $mimeParts !== false && strpos( $mimeParts, '/' ) !== false )
{
list( $this->contentType, $this->mimeType ) = explode( '/', $mimeParts );
}
else
{
// default to mimetype application/octet-stream
$this->contentType = self::CONTENT_TYPE_APPLICATION;
$this->mimeType = "octet-stream";
}
finfo_close( $fileInfo );
}
else
{
// default to mimetype application/octet-stream
$this->contentType = self::CONTENT_TYPE_APPLICATION;
$this->mimeType = "octet-stream";
}
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @throws ezcBaseFileNotFoundException
* when setting the property with an invalid filename.
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'fileName':
if ( is_readable( $value ) )
{
parent::__set( $name, $value );
}
else
{
throw new ezcBaseFileNotFoundException( $value );
}
break;
default:
return parent::__set( $name, $value );
break;
}
}
/**
* Returns the value of property $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @return mixed
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
default:
return parent::__get( $name );
break;
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
default:
return parent::__isset( $name );
}
}
/**
* Returns the contents of the file with the correct encoding.
*
* @return string
*/
public function generateBody()
{
return chunk_split( base64_encode( file_get_contents( $this->fileName ) ), 76, ezcMailTools::lineBreak() );
}
}
?>

View file

@ -0,0 +1,129 @@
<?php
/**
* File containing the ezcMailStreamFile class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Mail part for data in a stream.
*
* @property string $stream
* The stream object to be read and added as an attachment. The
* mimeType and contentType are set in the constructor or if not
* specified they are extracted with the fileinfo extension if it
* is available, otherwise they are set to application/octet-stream.
*
* @package Mail
* @version //autogen//
*/
class ezcMailStreamFile extends ezcMailFilePart
{
/**
* Constructs a new attachment with $fileName and $stream.
*
* If the $mimeType and $contentType are not specified they are set
* to application/octet-stream.
*
* @param string $fileName
* @param resource $stream
* @param string $contentType
* @param string $mimeType
*/
public function __construct( $fileName, $stream, $contentType = null, $mimeType = null )
{
parent::__construct( $fileName );
$this->stream = $stream;
if ( $contentType != null && $mimeType != null )
{
$this->contentType = $contentType;
$this->mimeType = $mimeType;
}
else
{
// default to mimetype application/octet-stream
$this->contentType = self::CONTENT_TYPE_APPLICATION;
$this->mimeType = "octet-stream";
}
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'stream':
$this->properties[$name] = $value;
break;
default:
return parent::__set( $name, $value );
break;
}
}
/**
* Returns the value of property $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @return mixed
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'stream':
return $this->properties[$name];
break;
default:
return parent::__get( $name );
break;
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'stream':
return isset( $this->properties[$name] );
default:
return parent::__isset( $name );
}
}
/**
* Returns the contents of the file with the correct encoding.
*
* The stream might become unusable after this if it doesn't support seek.
*
* @return string
*/
public function generateBody()
{
$contents = stream_get_contents( $this->stream );
return chunk_split( base64_encode( $contents ), 76, ezcMailTools::lineBreak() );
}
}
?>

View file

@ -0,0 +1,144 @@
<?php
/**
* File containing the ezcMailVirtualFile class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Mail part for binary data in memory.
*
* @property string $contents
* The contents to be added as an attachment. The mimeType and
* contentType are set in the constructor or if not specified they
* are extracted with the fileinfo extension if it is available,
* otherwise they are set to application/octet-stream.
*
* @package Mail
* @version //autogen//
*/
class ezcMailVirtualFile extends ezcMailFilePart
{
/**
* Constructs a new attachment with $fileName and $contents.
*
* If the $mimeType and $contentType are not specified they are extracted
* with the fileinfo extension if it is available, otherwise they are set
* to application/octet-stream.
*
* @param string $fileName
* @param string $contents
* @param string $contentType
* @param string $mimeType
*/
public function __construct( $fileName, $contents, $contentType = null, $mimeType = null )
{
parent::__construct( $fileName );
$this->contents = $contents;
if ( $contentType != null && $mimeType != null )
{
$this->contentType = $contentType;
$this->mimeType = $mimeType;
}
elseif ( ezcBaseFeatures::hasExtensionSupport( 'fileinfo' ) )
{
// get mime and content type
$fileInfo = new finfo( FILEINFO_MIME );
$mimeParts = $fileInfo->buffer( $contents );
if ( $mimeParts !== false && strpos( $mimeParts, '/' ) !== false )
{
list( $this->contentType, $this->mimeType ) = explode( '/', $mimeParts );
}
else
{
// default to mimetype application/octet-stream
$this->contentType = self::CONTENT_TYPE_APPLICATION;
$this->mimeType = "octet-stream";
}
}
else
{
// default to mimetype application/octet-stream
$this->contentType = self::CONTENT_TYPE_APPLICATION;
$this->mimeType = "octet-stream";
}
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'contents':
$this->properties[$name] = $value;
break;
default:
return parent::__set( $name, $value );
break;
}
}
/**
* Returns the value of property $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @return mixed
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'contents':
return $this->properties[$name];
break;
default:
return parent::__get( $name );
break;
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'contents':
return isset( $this->properties[$name] );
default:
return parent::__isset( $name );
}
}
/**
* Returns the contents of the file with the correct encoding.
*
* @return string
*/
public function generateBody()
{
return chunk_split( base64_encode( $this->contents ), 76, ezcMailTools::lineBreak() );
}
}
?>

View file

@ -0,0 +1,196 @@
<?php
/**
* File containing the ezcMailMultipart class.
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* Abstract base class for all multipart types.
*
* This class provides writing functionality that is common for all multipart
* types. Multiparts will be written to the mail in the order that they are set
* to the $parts variable.
*
* @property string $boundary
* The boundary string to use between parts. This string is
* automatically generated and should only be changed for special
* requirements.
* @property string $noMimeMessage
* Message to display to non-MIME capable email clients. The default
* value is stored in the constant {@link self::DEFAULT_NO_MIME_MESSAGE}.
*
* @package Mail
* @version //autogen//
*/
abstract class ezcMailMultipart extends ezcMailPart
{
/**
* Default message displayed to non-MIME capable email clients.
*/
const DEFAULT_NO_MIME_MESSAGE = "This message is in MIME format. Since your mail reader does not understand\r\nthis format, some or all of this message may not be legible.";
/**
* An array holding the parts of this multipart.
*
* @var array(ezcMailPart)
*/
protected $parts = array();
/**
* The counter is unique between all multipart types and is used to
* generate unique boundary strings.
*
* @var int
*/
private static $counter = 0;
/**
* Constructs a new ezcMailMultipart with the parts $parts.
*
* Subclasses typically accept an arbitrary number of parts in the
* constructor and pass them along using func_get_args().
*
* $parts should be of the format array(array(ezcMailPart)|ezcMailPart)
*
* Subclasses must call this method in the constructor.
* @param array $parts
*/
public function __construct( array $parts )
{
parent::__construct();
$this->noMimeMessage = self::DEFAULT_NO_MIME_MESSAGE;
$this->boundary = $this->generateBoundary();
$this->setHeader( "Content-Type", 'multipart/' . $this->multipartType() . '; '
. 'boundary="' . $this->boundary . '"' );
foreach ( $parts as $part )
{
if ( $part instanceof ezcMailPart )
{
$this->parts[] = $part;
}
elseif ( is_array( $part ) ) // add each and everyone of the parts in the array
{
foreach ( $part as $array_part )
{
if ( $array_part instanceof ezcMailPart )
{
$this->parts[] = $array_part;;
}
}
}
}
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'boundary':
$this->properties[$name] = $value;
$this->setHeader( 'Content-Type', 'multipart/' . $this->multipartType() . '; ' .
'boundary="' . $this->boundary . '"' );
break;
case 'noMimeMessage':
$this->properties[$name] = $value;
break;
default:
return parent::__set( $name, $value );
break;
}
}
/**
* Returns the property $name.
*
* @throws ezcBasePropertyNotFoundException
* if the property does not exist.
* @param string $name
* @return mixed
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'boundary':
case 'noMimeMessage':
return $this->properties[$name];
break;
default:
return parent::__get( $name );
break;
}
}
/**
* Returns true if the property $name is set, otherwise false.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'boundary':
case 'noMimeMessage':
return isset( $this->properties[$name] );
default:
return parent::__isset( $name );
}
}
/**
* Returns the generated body for all multipart types.
*
* @return string
*/
public function generateBody()
{
$data = $this->noMimeMessage . ezcMailTools::lineBreak();
foreach ( $this->parts as $part )
{
$data .= ezcMailTools::lineBreak() . '--' . $this->boundary . ezcMailTools::lineBreak();
$data .= $part->generate();
}
$data .= ezcMailTools::lineBreak() . '--' . $this->boundary . '--';
return $data;
}
/**
* Returns the type of multipart.
*
* @return string
*/
abstract public function multipartType();
/**
* Returns a unique boundary string.
*
* @return string
*/
protected static function generateBoundary()
{
return date( "YmdGHjs" ) . ':' . getmypid() . ':' . self::$counter++;
}
}
?>

View file

@ -0,0 +1,84 @@
<?php
/**
* File containing the ezcMailMultipartAlternative class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* ezcMailMultipartAlternative is used to bundle a group of mail parts
* where only one should be shown.
*
* This is useful e.g if you have a text in some fancy format but you also want
* to provide a backup plain text format to make sure everyone can read the
* mail. The alternatives should be added in an order of increasing
* faithfulness to the original content. In general, the best choice is the
* LAST part of a type supported by the recipients mail client.
*
* The following example shows a HTML mail with a plain text backup in case
* the recipients client can't display HTML mail.
* <code>
* $mail = new ezcMail();
* $mail->from = new ezcMailAddress( 'sender@example.com', 'Adrian Ripburger' );
* $mail->addTo( new ezcMailAddress( 'receiver@example.com', 'Maureen Corley' ) );
* $mail->subject = "Example of an HTML email with attachments";
* $plainText = new ezcMailText( "This is the plain text part" );
* $htmlText = new ezcMailText( "<html>This is the HTML part</html>" );
* $htmlText->subType = 'html';
* $mail->body = new ezcMailMultipartAlternative( $plainText, $htmlText );
* </code>
*
* @package Mail
* @version //autogen//
*/
class ezcMailMultipartAlternative extends ezcMailMultipart
{
/**
* Constructs a new ezcMailMultipartAlternative
*
* The constructor accepts an arbitrary number of ezcMailParts or arrays with ezcMailparts.
* Parts are added in the order provided. Parameters of the wrong
* type are ignored.
*
* @param ezcMailPart|array(ezcMailPart) $...
*/
public function __construct()
{
$args = func_get_args();
parent::__construct( $args );
}
/**
* Appends a part to the list of parts.
*
* @param ezcMailPart $part
*/
public function appendPart( ezcMailPart $part )
{
$this->parts[] = $part;
}
/**
* Returns the mail parts associated with this multipart.
*
* @return array(ezcMailPart)
*/
public function getParts()
{
return $this->parts;
}
/**
* Returns "alternative".
*
* @return string
*/
public function multipartType()
{
return "alternative";
}
}
?>

View file

@ -0,0 +1,98 @@
<?php
/**
* File containing the ezcMailMultipartDigest class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* The digest multipart type is used to bundle a list of mail objects.
*
* Each part will be shown in the mail in the order provided. It is not
* necessary to bundle digested mail using a digest object. However, it is
* considered good practice to do so when several digested mail are sent
* together.
*
* @package Mail
* @version //autogen//
*/
class ezcMailMultipartDigest extends ezcMailMultipart
{
/**
* Constructs a new ezcMailMultipartDigest
*
* The constructor accepts an arbitrary number of ezcMail/ezcMailRfc822Digest objects
* or arrays with objects of these types.
*
* Objects of the type ezcMail are wrapped into an ezcMailRfc822Digest object.
*
* Parts are added in the order provided. Parameters of the wrong
* type are ignored.
*
* @param ezcMailRfc822Digest|array(ezcMailRfc822Digest) $...
*/
public function __construct()
{
$args = func_get_args();
parent::__construct( array() );
foreach ( $args as $part )
{
if ( $part instanceof ezcMail )
{
$this->parts[] = new ezcMailRfc822Digest( $part );
}
else if ( $part instanceof ezcMailRfc822Digest )
{
$this->parts[] = $part;
}
else if ( is_array( $part ) ) // add each and everyone of the parts in the array
{
foreach ( $part as $array_part )
{
if ( $array_part instanceof ezcMail )
{
$this->parts[] = new ezcMailRfc822Digest( $array_part );
}
else if ( $array_part instanceof ezcMailRfc822Digest )
{
$this->parts[] = $array_part;
}
}
}
}
}
/**
* Appends a part to the list of parts.
*
* @param ezcMailRfc822Digest $part
*/
public function appendPart( ezcMailRfc822Digest $part )
{
$this->parts[] = $part;
}
/**
* Returns the mail parts associated with this multipart.
*
* @return array(ezcMail)
*/
public function getParts()
{
return $this->parts;
}
/**
* Returns "digest".
*
* @return string
*/
public function multipartType()
{
return "digest";
}
}
?>

View file

@ -0,0 +1,76 @@
<?php
/**
* File containing the ezcMailMultipartMixed class
*
* @package Mail
* @version //autogen//
* @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* The mixed multipart type is used to bundle an ordered list of mail
* parts.
*
* Each part will be shown in the mail in the order provided.
*
* The following example shows how to build a mail with a text part
* and an attachment using ezcMailMultipartMixed.
* <code>
* $mixed = new ezcMailMultipartMixed( new ezcMailTextPart( "Picture of me flying!" ),
* new ezcMailFile( "fly.jpg" ) );
* $mail = new ezcMail();
* $mail->body = $mixed;
* </code>
*
* @package Mail
* @version //autogen//
*/
class ezcMailMultipartMixed extends ezcMailMultipart
{
/**
* Constructs a new ezcMailMultipartMixed
*
* The constructor accepts an arbitrary number of ezcMailParts or arrays with ezcMailparts.
* Parts are added in the order provided. Parameters of the wrong
* type are ignored.
*
* @param ezcMailPart|array(ezcMailPart) $...
*/
public function __construct()
{
$args = func_get_args();
parent::__construct( $args );
}
/**
* Appends a part to the list of parts.
*
* @param ezcMailPart $part
*/
public function appendPart( ezcMailPart $part )
{
$this->parts[] = $part;
}
/**
* Returns the mail parts associated with this multipart.
*
* @return array(ezcMailPart)
*/
public function getParts()
{
return $this->parts;
}
/**
* Returns "mixed".
*
* @return string
*/
public function multipartType()
{
return "mixed";
}
}
?>

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