January 30, 2009

Sending mail Attachment(s) with PHP mail function (PART - II) : The Code

In my previous post we saw the thumb rules for emailing using php mail function. Now we will implement those rules in code.

I have written a function sendMail, which receives mail subject, message, senders email id and destination id. I also accept three optional parameters, namely cc, bcc and attachment file list. The function prepares appropriate mail headers and call mail function to send mail via SMTP server. The function returns true for mailing success and otherwise it will return false.


function
sendMail( $subject, $message, $from, $to, $cc=null, $bcc=null, $attachment=null)

{

$headers = 'From: '.$from."\r\n";

if(!is_null($cc)){

$headers .= 'Cc: '.$cc ."\r\n";

}

if(!is_null($bcc)){

$headers .= 'Bcc: '.$bcc ."\r\n";

}

$headers .= 'MIME-Version: 1.0'."\r\n";

if(is_array($attachment) && count($attachment)>0){

$headers .= mailAttachmentHeader ($attachment, $message);

} else {

$headers .= 'Content-type: text/html; charset=iso-8859-1'."\r\n";

}

if(is_array($attachment) && count($attachment)>0){

$message = '';

}

$mailStatus = mail($to,$subject,$message,$headers);

echo "\nNew Mailer\n";

if($mailStatus){

return true;

}else{

return false;

}

}


In mail function "Form ", "Cc " , "Bcc", "'MIME-Version" set without checking if attachment is present or not – Rule 1.

Next we check is if attachments are present.
In case of no attachment we set 'Content-type: text/html; charset=iso-8859-1'."\r\n" Rule 2.a. Otherwise we call the mailAttachmentHeader function to prepare the attachment header

The massage is set to blank Rule 3.b.

function mailAttachmentHeader($attachment, $message )

{

$mime_boundary = md5(time());

$xMessage = "Content-Type: multipart/mixed; boundary=\"".$mime_boundary."\"\r\n\r\n";

$xMessage .= "--".$mime_boundary."\r\n\r\n";

$xMessage .= "Content-Type: text/plain; charset=\"iso-8859-1\"\r\n";

$xMessage .= "Content-Transfer-Encoding: 7bit\r\n";

$xMessage .= $message."\r\n\r\n";

foreach($attachment as $file)

{

$xMessage .= "--".$mime_boundary."\r\n";

$xMessage .= "Content-Type: application/octet-stream; name=\"".basename($file)."\"\r\n";

$xMessage .= "Content-Transfer-Encoding: base64\r\n";

$xMessage .= "Content-Disposition: attachment; filename=\"".basename($file)."\"\r\n";

$content = file_get_contents($file);

$xMessage.= chunk_split(base64_encode($content));

$xMessage .= "\r\n\r\n";

}

$xMessage .= "--".$mime_boundary."--\r\n\r\n";

return $xMessage;

}


Parameters passed to mailAttachmentHeader function are list of attachments and the functions returns headers string.

In mailAttachmentHeader function we set "Content-Type: multipart/mixed; bundary=\"".$mime_boundary."\"\r\n\r\n"; where value of $mime_boundary is the MD5 of current timestamp. Rule 2.b.

To denote starting of message and each attachment following code is added
$xMessage .= "--".$mime_boundary."\r\n\r\n"; Rule 3.b.

We add Content-type “text/html” for message and “application/octet-stream” for attachments – Rule 4

For each attachment we add "Content-Transfer-Encoding: base64\r\n"; Rule 5 and "Content-Disposition: attachment; filename=\"".basename($file)."\"\r\n"; Rule 6

At the end of the function we add "--".$mime_boundary."--\r\n\r\n"; to denote the end of attachment mail header Rule 7

Now you can use the send mail function to send mail with or without any attachment. Cheers!!

(c) Sourav Ray Creative Commons License

January 28, 2009

Sending mail Attachment(s) with PHP mail function (PART -I) : Rules Of Thumb

A few days ago I was writing a script that would send email with (or without) any number of attachments. I started googling for help and ended up with some code snippets that didn’t work. After spending few more frustrating hours debugging those scripts, I finally reached the solution (“Tank you! Anand, Kunal and Avlesh… for your suggestions”). The problem with those scripts was that they were missing some crucial pieces of mail header and it was really a daunting task to fix those bugs, because “trial 'n error” was the only option left. That’s why in this post I tried to formulate a set of rules to send mail using mail() function with or without any attachment.

The Rules:

  1. In the mail header few header elements (like "Form ", "Cc " , "Bcc", "'MIME-Version" ) will remain as it is, irrespective of the fact that the mail has any attachment or not.
  1. a. If a mail doesn't contain any attachment, then Content-type will be "text/html" (for html formatted mail) or "text/plain" ( for plain text mail) . Content-type should have an additional attribute "charset" to define character encoding of the message.

b. In case when mail consists of one or more attachments, Content-type will be "multipart/mixed". Content-type will also have an attribute called "boundary". The "boundary" attribute contains a unique signature which is use to denote the starting point of each message/attachment of the mail as well as the end of mail.

  1. a. In case of mail without attachment the message string should be passed to mail function as message parameter.

b. If mail contains one or more attachments, then the message and the attachment file contents will be attached to the header string, separated by a boundary notation

-- [boundary value]

the start message will also have similar boundary notation to denote the start of message and A blank string or null value should be passed to the message parameter of mail function.

  1. In multipart mail each message/attachment will have their own Content-type . For a multipart mail header the message will have Content-type "text/html" (for html formatted mail) or "text/plain" (for plain text mail). And attachment will have Content-type depending upon the type of content. If you are not sure about content use Content-type "application/octet-stream". For attachment content type Additional Attribute name can be use to denote the base name of the attachment file.
  1. Each attachment block also contain header "Content-Transfer-Encoding" to specify the content encoding
  1. Each attachment block will have Content-Disposition as "attachment" and attribute filename will denote the name of the downloaded file.
  1. After the end of all attachments there will be end of mail notation

--[boundary value]--



Note : To be on the safe side it is better to encode the attachment content to some standard encoding and set the Content-Transfer-Encoding as per the implemented encoding.

In the next Post we will see how to implement these Rules in actual code

(c) Sourav Ray Creative Commons License

January 22, 2009

PHP! Taking arguments from Command Line

Setting up Command Line Interface SAPI for php
In *nix environment:
Since PHP 4.3.0 the both --enable-cli and --enable-cgi are enabled by default. If a module SAPI is chosen during configure, such as apxs, or the --disable-cgi option is used, the CLI is copied to {PREFIX}/bin/php during make install otherwise the CGI is placed there. If you want to override the installation of the CGI binary, use make install-cli after make install. Alternatively you can specify --disable-cgi in your configure line.
In windows:
PHP 5, the CLI is distributed in the main folder, named php.exe. The CGI version is distributed as php-cgi.exe.


Now consider this CLI hello world programme
File: cli-hello-world.co
<?php
fwrite(STDOUT,"CLI hello world \n");
?>

To call this script from command line (we assume that php bin path is set in OS environment variable )

>_ php cli-hello-world.com

CLI hello world


To passing an argument to php script from command line is similar to C or Java. There are two global variables $argc and $argv, that hold an integer value of number of arguments passed and an array of sting value of the arguments respectively.
Note: if no additional parameter is passed then the arg variables only will contain the file name and the value of $argc will be 1

For example
File : cli-arg.php
<?php
if($argc > 1)
{
foreach ($argv as $argumentVariable)
fwrite(STDOUT, $argumentVariable. "/n");
}
?>

Now we can call this script like
>_ php cli-arg.php "Hello World"
cli-arg.php
Hello World

In PHP 5, the CLI version will always populate the global $argv and $argc variables regardless of any php.ini directive setting. Even having register_argc_argv set to off will have no affect in CLI.



(c) Sourav Ray Creative Commons License

" हेल्लो World "

Finally I have stared a blog that will keep an account to all my coding tricks. This was a long pending task since my previous blog was closed. My official blog is yet to be online, it is coming soon...


(c) Sourav Ray Creative Commons License