Page 4 of 4

Posted: Wed May 10, 2006 4:42 pm
by Christopher
d11wtq wrote:My main question is about the event handlers... does it sound like a good idea or just me getting over-excited?
Unfortunately I think over-excited (though it is pretty cool ;)). I really don't see the sense of the extra overhead because:

Code: Select all

$this->runPluginMethods('onAuthenticate');

// is really no different than

$this->plugin->onAuthenticate();
And honestly the way you have it is less clear and flexible I think.

Posted: Wed May 10, 2006 5:23 pm
by Chris Corbyn
arborint wrote:
d11wtq wrote:My main question is about the event handlers... does it sound like a good idea or just me getting over-excited?
Unfortunately I think over-excited (though it is pretty cool ;)). I really don't see the sense of the extra overhead because:

Code: Select all

$this->runPluginMethods('onAuthenticate');

// is really no different than

$this->plugin->onAuthenticate();
And honestly the way you have it is less clear and flexible I think.
:( Hmm yeah I did figure as much. It's interesting, I was thinking about overhead and in this instance it's not going to make any difference unless the overhead is really huge since the MTA were connected to will likely run slower than the script itself.

I gave it a little test with a simple plugin loaded that did nothing more than echo an incremented number on each command sent to the MTA and I was getting approx 10 emails per second from a 1.4GHz Celeron, 512MB DDR over a 128Kbit upstream to my ISP's SMTP server.... I'm not convinced that this script takes that long to dolly out those commands, more likely it's just as fast the ISP's SMTP server can handle the load.

Note: You can load in as many plugins as you need to, that why I mad a method runPluginMethods() rather than sticking a foreach() at each point in the script.

Still pretty cool though :P :lol:

EDIT | Here wasd the API I was writing:

Code: Select all

Swift - Plugin API
	--------------------------
	
	Author: Chris Corbyn
	Current Release: 0.0.1
	Last Updated: 10th May 2006
	
	
--------------------------------------------

Required Properties (public):
	
	pluginName: string
	
		Identifies to Swift what the plugin is called.
	
Required methods (public):
	
	void loadBaseObject( &object SwiftInstance )
	
		Swift passes an instance of itself to the plugin via this method.  For
		your plugin to do anything useful it would be a good idea to store this
		instance in a property.
	
Optional Methods (public):
	
	void onLoad( void )
	
		Executes as soon as the plugin has been loaded by Swift and Swift has
		called loadBaseObject().
	
	void onBeforeSend( void )
	
		Executes as soon as Swift is about to issue the set of commands stored
		in SwiftInstance::currentMail.
	
	void onSend( void )
		
		Executes as soon as Swift has successfully sent a message.
	
	void onBeforeCommand( void )
		
		Executes before a command is about to be sent.
	
	void onCommand( void )
		
		Executes after a successful command execution.
	
	void onClose( void )
	
		Executes once Swift has closed the connection with the MTA
	
	void onLog( void )
	
		Executes when Swift logs a transaction with the MTA.
	
	void onError( void )
		
		Executes when Swift reports an error message.
	
	void onFail( void )
	
		Executes when Swift completely fails.
		
		NOTE: Swift stops proccessing commands as long as swiftInstance::failed is
			TRUE.
	
	void onFlush( void )
	
		Executes before SwiftInstance::flush() runs.
	
	void onAuthenticate( void )
		
		Executes if Swift successfully authenticates to an MTA using
		swiftInstance::authenticate().

----------------------------------------

Swift Properties accessible to the plugin:
	
	*** NOTE: The file "Swift_docs.txt" contains information about generic properties
		and methods of Swift... they will not be repeated in this document. ***
	
	failed: bool
	
		This is boolean TRUE if Swift has failed execution at all.  If this is TRUE
		Swift processes no further MTA commands (you can override it).
	
	currentMail: Array(
		0 => MAIL FROM,
		1 => RCPT TO,
		2 => DATA
		3 => {Message Body} )
	
		Contains the set of commands Swift last sent.  If this is read from
		a onBeforeSend() method these commands will not yet have been sent and
		thus can be adjusted.
	
	currentCommand: string
	
		Contains the command that was last sent.  Note that is this property is
		read in an onBeforeCommand() method the command will not yet have been sent
		and can be adjusted.
	
----------------------------------------------

Swift methods accessible to the plugin:
	
	*** NOTE: The file "Swift_docs.txt" contains information about generic properties
		and methods of Swift... they will not be repeated in this document. ***
	
	void logError( string ErrorMSG, int ErrorNUM )
	
		Logs an error in SwiftInstance::errors.  This does *not* make Swift fail.
	
	void fail( void )
		
		Set SwiftInstance::failed to TRUE and causes any onFail() methods in loaded
		plugins to run.
	
	string encode( string Data, string EncodingType )
	
		Returns a string containing data encoded in the requested format.
		Formats supported are:
			base64,
			quoted-printable,
			7-bit
	
	string escapeDot (string Data )
	
		When an MTA requests accepts DATA it stops reading when CRLF<dot>CRLF is
		sent.  This method returns a string with any of these sequences padded out.
	
--------------------------------------------
End of document

Code: Select all

Swift - A PHP Mailer Class
	--------------------------
	
	Author: Chris Corbyn
	Current Release: 0.0.1
	Last Updated: 10th May 2006
	
	
--------------------------------------------

Installation:

	To use Swift in your own project you simply need to untar the archive which you
	downloaded and copy the directory to a location accessible to PHP.  You should
	make sure that both the base directory (Swift-<version>/) and the Swift/
	directory can be accessed so that you can include() the appropriate files.

	Once you have copied Swift to your server you should include at least the
	main Swift.php file and one connection file from the Swift/ directory in any
	scripts which will need to send mail.

---------------------------------------------

Public Properties Available for normal use:
	
	errors:  Array (
		num => error number,
		time => time of error,
		message => string )
	
		This property contains information about any errors which occured during
		execution of Swift.  An example might be if the SMTP server refuses your
		connection.
	
	lastError: String error
	
		Contains the last error that occured
	
	transactions: Array (
		command => command sent,
		time => time of command,
		response => response given by MTA )
	
		This property contains *every* command sent to the server along with
		the responses that are received.  It's worthwhile checking here if something
		isn't working as expected.
	
	reponseCode: Integer response
	
		Contains the number of the response last given by the MTA.
	
	lastResponse: String response
	
		Contains the string returned by the MTA after the previous command
	
	headers: String headers
	
		Contains the headers that are prepended to emails being sent. Note that
		headers by have line endings of CRLF ( \r\n ) not just LF ( \n ).  You
		should only add headers using addHeaders().
	
------------------------------------------

Public methods available for normal use:
	
	void __construct( object ConnectionHandler, string Domain )
	
		Runs when Swift is first instantiated.  The ConnectionHandler is a
		separate class which contains the connection to the MTA.
		
		Domain is the FQDN (Fully Qualified Domain Name) of the server the script
		is being run from.
	
		NOTE: In PHP4 this is name Swift()
	
	void close( void )
	
		Closes the connection to the MTA - this should really be the last thing
		you do when you're finished using Swift.
	
	void addHeaders( string Headers)
		
		Appends Headers to the headers property in the class.  This method checks
		that the headers end with CRLF and appends this if not.
	
	void setMimeBoundary( string Boundary )
	
		Set the mimeBoundary property to Boundary.  This only works for the first
		part in any multipart email since the other boundaries must be unique.
	
	void setMimeWarning( string Warning )
	
		Sets the mimeWarning property to Warning.  This is the bit of text which
		old email clients will see if they don't support MIME.
	
	void addExpectedCode( string Command, int Code )
	
		Adds an element to the expectedCodes array property.  If the code returned
		by the MTA upon the receipt of Command does not match Code, Swift fails
		and does no further processing.
	
	void loadPlugin( &object PluginObject )
	
		Loads a Swift Plugin into the class.  PluginObject must adhere to a
		small API.  See "Plugin_API" for more info.
	
	&object getPlugin( string PluginName )
	
		Passes back a reference to PluginName so that methods can be run inside
		the plugin.
	
	void loadAuthenticator( &object AuthenticatorObject )
	
		Loads an authentication mechanism into Swift.  AuthenticatorObject must
		adhere to a small API.  See "Authenticator_API" for more info.
		
		NOTE: If the Swift/ directory is in the same location as Swift.php,
			Swift will attempt to load any files named Swift_<Name>_Authenticator.php
			if authenticate() is called and this method has not been previously
			executed.
	
	bool authenticate( string Username, string Password )
	
		Attempts to authenticate onto the MTA using the credential provided.
		If the authentication succeeds, this method returns TRUE, otherwise it
		return FALSE and logs an error before failing.
		
		NOTE: Swift checks to see which authentication mechanisms the MTA supports
			and only authenticates via one of these mechanisms.
	
	void flush( bool ClearHeaders )
	
		Empties out the contents of emails that Swift is working with.  If ClearHeaders
		is set TRUE Swift will also reset the email headers.  This method runs
		automatically once send() has finished.
	
	bool send( mixed ToAddress, string FromAddress, string Subject [, string Body [, string BodyType [, string BodyEncoding ] ] ] )
	
		Sends mail to ToAddress.  If ToAddress is a string, Swift will end the
		email to that recipient only.  If ToAddress is an array of strings
		Swift will batch email all addresses.
		
		If Body is omitted, Swift will attempt to build a MIME message.  This can
		be created using addPart() and addAttachment().
		
		BodyType is the Content-Type header of the email and defaults to text/plain.
		
		BodyEncoding is the encoding format of the email and defaults to 7bit ascii.
	
		If all messages send successfully send() return TRUE.  If at least one mail
		fails to send send() returns FALSE.
		
	string command( string MTACommand )
	
		Send MTACommand to the MTA and returns the response the MTA issues.
		
		NOTE: MTA commands must end with CRLF ( \r\n ) and not LF ( \n ).  Swift
			will add CRLF if MTACommand does not already end with CRLF.
	
	void addPart( string PartBody [, string PartType [, string PartEncoding ] ] )
	
		Adds a new part PartBody to a multipart MIME message.
		
		PartType is the Content-Type of the part and defaults to text/plain.
		
		PartEncoding is the encoding of the part and defaults to 7biut ascii.
	
	void addAttachment( string Data, string Filename, string Filetype )
	
		Adds an attachment to a multipart MIME message.  The attachment contents
		can be retreived by running file_get_contents() to produce a binary-safe
		string.  Filename is the name that will be used by the recipient's
		email client.  Filetype is the Content-Type of the file (for example
		image/jpeg).
	
	bool hasFailed( void )
	
		Returns whether or not Swift has failed executing.  If this method returns
		TRUE, Swift has already stopped sending commands to the MTA.
	
	
------------------------------------------------
End of document

Posted: Wed May 10, 2006 6:51 pm
by Christopher
The plugins still seem overkill for some reason. I guess I would have to see how people might use them. I am wondering if either individual plugins for each place where they are needed, or simpler just a single plugin that was passed the state so it could deal with whatever it needed. I also don't see why the mailer class needs to support multiple plugins. If someone needed it they could do the looping inside their plugin.

Code: Select all

class SwiftPlugin {

function execute ($state, $mailer) {
switch ($state) {
case onLoad:
    break;
case onBeforeSend:
    break;
case onBeforeCommand:
    break;
case onCommand:
    break;
case onClose:
    break;
case onLog:
    break;
case onError:
    break;
case onFail:
    break;
case onFlush:
    break;
case onAuthenticate:
    break;
}

}

Posted: Thu May 11, 2006 1:22 am
by Chris Corbyn
arborint wrote:The plugins still seem overkill for some reason. I guess I would have to see how people might use them. I am wondering if either individual plugins for each place where they are needed, or simpler just a single plugin that was passed the state so it could deal with whatever it needed. I also don't see why the mailer class needs to support multiple plugins. If someone needed it they could do the looping inside their plugin.

Code: Select all

class SwiftPlugin {

function execute ($state, $mailer) {
switch ($state) {
case onLoad:
    break;
case onBeforeSend:
    break;
case onBeforeCommand:
    break;
case onCommand:
    break;
case onClose:
    break;
case onLog:
    break;
case onError:
    break;
case onFail:
    break;
case onFlush:
    break;
case onAuthenticate:
    break;
}

}
I was kind of hoping that it wouldn't just be the user writing a plugin for themeselves only; rather developers will write plugins that can be used by other people for some common purpose. For example, a "copy this message to myself". On the other hand, there are times when you can't just interact with the class manually from the outside because the mailer is in the middle of some crucial flow of logic, in which case we need the mailer class to inform the plugin that it's time to do a certain task. A good example would be email pre-processing, since send() calls bulidMail() and then instantly sends it off - whereas with the onBeforeSend() method you get a chance to make some edits before the mail is sent off. You can still do the things you're saying above by manually calling methods inside the plugin.

Maybe I'm just too keen to keep this because I can see how well it works and the level of dynamicity I can have in a plugin.

I trust what you're saying though, you know your stuff :)

Posted: Thu May 11, 2006 1:29 am
by Christopher
d11wtq wrote:Maybe I'm just too keen to keep this because I can see how well it works and the level of dynamicity I can have in a plugin.
I'm really just throwing ideas your way. I trust that you know best were you are headed.

Posted: Thu May 11, 2006 2:18 am
by Chris Corbyn
arborint wrote:
d11wtq wrote:Maybe I'm just too keen to keep this because I can see how well it works and the level of dynamicity I can have in a plugin.
I'm really just throwing ideas your way. I trust that you know best were you are headed.
I'm interested :) Discussion is healthy.... I reckon the whole plugin topic could be in a thread of its own with a few more particpants :D