I just started today working with PHP's IMAP library, and while imap_fetchbody or imap_body are called, it is triggering my Kaspersky antivirus. The viruses are Trojan.Win32.Agent.dmyq and Trojan.Win32.FraudPack.aoda. I am running this off a local development machine with XAMPP and Kaspersky AV.
Now, I am sure there are viruses there since there is spam in the box (who doesn't need a some viagra or vicodin these days?). And I know that since the raw body includes attachments and different mime-types, bad stuff can be in the body.
So my question is: are there any risks using these libraries?
I am assuming that the IMAP functions are retrieving the body, caching it to disk/memory and the AV scanning it sees the data.
Is that correct? Are there any known security concerns using this library (I couldn't find any)? Does it clean up cached message parts perfectly or might viral files be sitting somewhere?
Is there a better way to get plain text out of the body than this? Right now I am using the following code (credit to Kevin Steffer):
function get_mime_type(&$structure) {
$primary_mime_type = array("TEXT", "MULTIPART","MESSAGE", "APPLICATION", "AUDIO","IMAGE", "VIDEO", "OTHER");
if($structure->subtype) {
return $primary_mime_type[(int) $structure->type] . '/' .$structure->subtype;
}
return "TEXT/PLAIN";
}
function get_part($stream, $msg_number, $mime_type, $structure = false, $part_number = false) {
if(!$structure) {
$structure = imap_fetchstructure($stream, $msg_number);
}
if($structure) {
if($mime_type == get_mime_type($structure)) {
if(!$part_number) {
$part_number = "1";
}
$text = imap_fetchbody($stream, $msg_number, $part_number);
if($structure->encoding == 3) {
return imap_base64($text);
} else if($structure->encoding == 4) {
return imap_qprint($text);
} else {
return $text;
}
}
if($structure->type == 1) /* multipart */ {
while(list($index, $sub_structure) = each($structure->parts)) {
if($part_number) {
$prefix = $part_number . '.';
}
$data = get_part($stream, $msg_number, $mime_type, $sub_structure,$prefix . ($index + 1));
if($data) {
return $data;
}
} // END OF WHILE
} // END OF MULTIPART
} // END OF STRUTURE
return false;
} // END OF FUNCTION
$connection = imap_open($server, $login, $password);
$count = imap_num_msg($connection);
for($i = 1; $i <= $count; $i++) {
$header = imap_headerinfo($connection, $i);
$from = $header->fromaddress;
$to = $header->toaddress;
$subject = $header->subject;
$date = $header->date;
$body = get_part($connection, $i, "TEXT/PLAIN");
}
Your guess seems accurate. IMAP itself is fine. What you do with the contents is what's dangerous.
What's dangerous about virus e-mails is that users might open a .exe attachment or something, so bad attachments and potentially evil HTML are what's being checked. As long as your code handling attachments doesn't tell the user to open them and this is just automatic processing or whatever, you're good to go. If you're planning on outputting HTML contents, be sure to use something like HTML Purifier.
The AV is detecting these signatures as they pass through the networking stack, most likely. You should be able to tell the source of the detection from the messages Kaspersky is giving you.
Related
How can you mimic a command line run of a script with arguements inside a PHP script? Or is that not possible?
In other words, let's say you have the following script:
#!/usr/bin/php
<?php
require "../src/php/whatsprot.class.php";
function fgets_u($pStdn) {
$pArr = array($pStdn);
if (false === ($num_changed_streams = stream_select($pArr, $write = NULL, $except = NULL, 0))) {
print("\$ 001 Socket Error : UNABLE TO WATCH STDIN.\n");
return FALSE;
} elseif ($num_changed_streams > 0) {
return trim(fgets($pStdn, 1024));
}
}
$nickname = "WhatsAPI Test";
$sender = ""; // Mobile number with country code (but without + or 00)
$imei = ""; // MAC Address for iOS IMEI for other platform (Android/etc)
$countrycode = substr($sender, 0, 2);
$phonenumber=substr($sender, 2);
if ($argc < 2) {
echo "USAGE: ".$_SERVER['argv'][0]." [-l] [-s <phone> <message>] [-i <phone>]\n";
echo "\tphone: full number including country code, without '+' or '00'\n";
echo "\t-s: send message\n";
echo "\t-l: listen for new messages\n";
echo "\t-i: interactive conversation with <phone>\n";
exit(1);
}
$dst=$_SERVER['argv'][2];
$msg = "";
for ($i=3; $i<$argc; $i++) {
$msg .= $_SERVER['argv'][$i]." ";
}
echo "[] Logging in as '$nickname' ($sender)\n";
$wa = new WhatsProt($sender, $imei, $nickname, true);
$url = "https://r.whatsapp.net/v1/exist.php?cc=".$countrycode."&in=".$phonenumber."&udid=".$wa->encryptPassword();
$content = file_get_contents($url);
if(stristr($content,'status="ok"') === false){
echo "Wrong Password\n";
exit(0);
}
$wa->Connect();
$wa->Login();
if ($_SERVER['argv'][1] == "-i") {
echo "\n[] Interactive conversation with $dst:\n";
stream_set_timeout(STDIN,1);
while(TRUE) {
$wa->PollMessages();
$buff = $wa->GetMessages();
if(!empty($buff)){
print_r($buff);
}
$line = fgets_u(STDIN);
if ($line != "") {
if (strrchr($line, " ")) {
// needs PHP >= 5.3.0
$command = trim(strstr($line, ' ', TRUE));
} else {
$command = $line;
}
switch ($command) {
case "/query":
$dst = trim(strstr($line, ' ', FALSE));
echo "[] Interactive conversation with $dst:\n";
break;
case "/accountinfo":
echo "[] Account Info: ";
$wa->accountInfo();
break;
case "/lastseen":
echo "[] Request last seen $dst: ";
$wa->RequestLastSeen("$dst");
break;
default:
echo "[] Send message to $dst: $line\n";
$wa->Message(time()."-1", $dst , $line);
break;
}
}
}
exit(0);
}
if ($_SERVER['argv'][1] == "-l") {
echo "\n[] Listen mode:\n";
while (TRUE) {
$wa->PollMessages();
$data = $wa->GetMessages();
if(!empty($data)) print_r($data);
sleep(1);
}
exit(0);
}
echo "\n[] Request last seen $dst: ";
$wa->RequestLastSeen($dst);
echo "\n[] Send message to $dst: $msg\n";
$wa->Message(time()."-1", $dst , $msg);
echo "\n";
?>
To run this script, you are meant to go to the Command Line, down to the directory the file is in, and then type in something like php -s "whatsapp.php" "Number" "Message".
But what if I wanted to bypass the Command Line altogether and do that directly inside the script so that I can run it at any time from my Web Server, how would I do that?
First off, you should be using getopt.
In PHP it supports both short and long formats.
Usage demos are documented at the page I've linked to. In your case, I suspect you'll have difficulty detecting whether a <message> was included as your -s tag's second parameter. It will probably be easier to make the message a parameter for its own option.
$options = getopt("ls:m:i:");
if (isset($options["s"] && !isset($options["m"])) {
die("-s needs -m");
}
As for running things from a web server ... well, you pass variables to a command line PHP script using getopt() and $argv, but you pass variables from a web server using $_GET and $_POST. If you can figure out a sensible way to map $_GET variables your command line options, you should be good to go.
Note that a variety of other considerations exist when taking a command line script and running it through a web server. Permission and security go hand in hand, usually as inverse functions of each other. That is, if you open up permissions so that it's allowed to do what it needs, you may expose or even create vulnerabilities on your server. I don't recommend you do this unless you'll more experienced, or you don't mind if things break or get attacked by script kiddies out to 0wn your server.
You're looking for backticks, see
http://php.net/manual/en/language.operators.execution.php
Or you can use shell_exec()
http://www.php.net/manual/en/function.shell-exec.php
Hi everyone once again!
We need some help to develop and implement a multi-curl functionality into our crawler. We have a huge array of "links to be scanned" and we loop throw them with a Foreach.
Let's use some pseudo code to understand the logic:
1) While ($links_to_be_scanned > 0).
2) Foreach ($links_to_be_scanned as $link_to_be_scanned).
3) Scan_the_link() and run some other functions.
4) Extract the new links from the xdom.
5) Push the new links into $links_to_be_scanned.
5) Push the current link into $links_already_scanned.
6) Remove the current link from $links_to_be_scanned.
Now, we need to define a maximum number of parallel connections and be able to run this process for each link in parallel.
I understand that we're gonna have to create a $links_being_scanned or some kind of queue.
I'm really not sure how to approach this problem to be honest, if anyone could provide some snippet or idea to solve it, it would be greatly appreciated.
Thanks in advance!
Chris;
Extended:
I just realized that is not the multi-curl itself the tricky part, but the amount of operations done with each link after the request.
Even after the muticurl, I would eventually have to find a way to run all this operations in parallel. The whole algorithm described below would have to run in parallel.
So now rethinking, we would have to do something like this:
While (There's links to be scanned)
Foreach ($Link_to_scann as $link)
If (There's less than 10 scanners running)
Launch_a_new_scanner($link)
Remove the link from $links_to_be_scanned array
Push the link into $links_on_queue array
Endif;
And each scanner does (This should be run in parallel):
Create an object with the given link
Send a curl request to the given link
Create a dom and an Xdom with the response body
Perform other operations over the response body
Remove the link from the $links_on_queue array
Push the link into the $links_already_scanned array
I assume we could approach this creating a new PHP file with the scanner algorithm, and using pcntl_fork() for each parallel proccess?
Since even using multi-curl, I would eventually have to wait looping on a regular foreach structure for the other processes.
I assume I would have to approach this using fsockopen or pcntl_fork.
Suggestions, comments, partial solutions, and even a "good luck" will be more than appreciated!
Thanks a lot!
DISCLAIMER: This answer links an open-source project with which I'm involved. There. You've been warned.
The Artax HTTP client is a socket-based HTTP library that (among other things) offers custom control over the number of concurrent open socket connections to individual hosts while making multiple asynchronous HTTP requests.
Limiting the number of concurrent connections is easily accomplished. Consider:
<?php
use Artax\Client, Artax\Response;
require dirname(__DIR__) . '/autoload.php';
$client = new Client;
// Defaults to max of 8 concurrent connections per host
$client->setOption('maxConnectionsPerHost', 2);
$requests = array(
'so-home' => 'http://stackoverflow.com',
'so-php' => 'http://stackoverflow.com/questions/tagged/php',
'so-python' => 'http://stackoverflow.com/questions/tagged/python',
'so-http' => 'http://stackoverflow.com/questions/tagged/http',
'so-html' => 'http://stackoverflow.com/questions/tagged/html',
'so-css' => 'http://stackoverflow.com/questions/tagged/css',
'so-js' => 'http://stackoverflow.com/questions/tagged/javascript'
);
$onResponse = function($requestKey, Response $r) {
echo $requestKey, ' :: ', $r->getStatus();
};
$onError = function($requestKey, Exception $e) {
echo $requestKey, ' :: ', $e->getMessage();
}
$client->requestMulti($requests, $onResponse, $onError);
IMPORTANT: In the above example the Client::requestMulti method is making all the specified requests asynchronously. Because the per-host concurrency limit is set to 2, the client will open up new connections for the first two requests and subsequently reuse those same sockets for the other requests, queuing requests until one of the two sockets become available.
you could try something like this, haven't checked it, but you should get the idea
$request_pool = array();
function CreateHandle($url) {
$handle = curl_init($url);
// set curl options here
return $handle;
}
function Process($data) {
global $request_pool;
// do something with data
array_push($request_pool , CreateHandle($some_new_url));
}
function RunMulti() {
global $request_pool;
$multi_handle = curl_multi_init();
$active_request_pool = array();
$running = 0;
$active_request_count = 0;
$active_request_max = 10; // adjust as necessary
do {
$waiting_request_count = count($request_pool);
while(($active_request_count < $active_request_max) && ($waiting_request_count > 0)) {
$request = array_shift($request_pool);
curl_multi_add_handle($multi_handle , $request);
$active_request_pool[(int)$request] = $request;
$waiting_request_count--;
$active_request_count++;
}
curl_multi_exec($multi_handle , $running);
curl_multi_select($multi_handle);
while($info = curl_multi_info_read($multi_handle)) {
$curl_handle = $info['handle'];
call_user_func('Process' , curl_multi_getcontent($curl_handle));
curl_multi_remove_handle($multi_handle , $curl_handle);
curl_close($curl_handle);
$active_request_count--;
}
} while($active_request_count > 0 || $waiting_request_count > 0);
curl_multi_close($multi_handle);
}
You should look for some more robust solution to your problem. RabbitMQ
is a very good solution I used. There is also Gearman but I think it is your choice.
I prefer RabbitMQ.
I will share with you my code which I have used to collect email addresses from certain website.
You can modify it to fit your needs.
There were some problems with relative URL's there.
And I do not use CURL here.
<?php
error_reporting(E_ALL);
$home = 'http://kharkov-reklama.com.ua/jborudovanie/';
$writer = new RWriter('C:\parser_13-09-2012_05.txt');
set_time_limit(0);
ini_set('memory_limit', '512M');
function scan_page($home, $full_url, &$writer) {
static $done = array();
$done[] = $full_url;
// Scan only internal links. Do not scan all the internet!))
if (strpos($full_url, $home) === false) {
return false;
}
$html = #file_get_contents($full_url);
if (empty($html) || (strpos($html, '<body') === false && strpos($html, '<BODY') === false)) {
return false;
}
echo $full_url . '<br />';
preg_match_all('/([A-Za-z0-9_\-]+\.)*[A-Za-z0-9_\-]+#([A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9]\.)+[A-Za-z]{2,4}/', $html, $emails);
if (!empty($emails) && is_array($emails)) {
foreach ($emails as $email_group) {
if (is_array($email_group)) {
foreach ($email_group as $email) {
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$writer->write($email);
}
}
}
}
}
$regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>";
preg_match_all("/$regexp/siU", $html, $matches, PREG_SET_ORDER);
if (is_array($matches)) {
foreach($matches as $match) {
if (!empty($match[2]) && is_scalar($match[2])) {
$url = $match[2];
if (!filter_var($url, FILTER_VALIDATE_URL)) {
$url = $home . $url;
}
if (!in_array($url, $done)) {
scan_page($home, $url, $writer);
}
}
}
}
}
class RWriter {
private $_fh = null;
private $_written = array();
public function __construct($fname) {
$this->_fh = fopen($fname, 'w+');
}
public function write($line) {
if (in_array($line, $this->_written)) {
return;
}
$this->_written[] = $line;
echo $line . '<br />';
fwrite($this->_fh, "{$line}\r\n");
}
public function __destruct() {
fclose($this->_fh);
}
}
scan_page($home, 'http://kharkov-reklama.com.ua/jborudovanie/', $writer);
I have a coming soon form at a website where user fills out an email form and it will be emailed to me. However, a spammer has hit the site and is spamming the form with goatse and so on. IP ban isn't helping so I need to stop the form sending it if it contains goatse or something. Here's the mailer.
<?php
$SPOSTI =$_POST[sposti];
if ($SPOSTI=="")
{
return false;
}
if ($SPOSTI=="goatse.fr")
{
return false;
}
if ($SPOSTI=="http://www.goatse.info/hello.jpg")
{
return false;
}
else
{
$to = "xxx#gmail.com";
$subject = "xxx";
$message = "$_POST[sposti] haluaa tiedon kun kotisivut.name avautuu.
$_POST[ip]";
$from = "$_POST[sposti]";
$headers = "From:" . $from;
mail($to,$subject,$message,$headers);
}
?>
Is there someway to block it from executing the code if the email contains a certain word (goatse in this case)
You need to use exit or die instead of return false which works inside functions/methods:
if ( $SPOSTI =="" || strpos('goatse', $SPOSTI) !== FALSE)
{
exit();
}
strpos() will let you find a substring, but I really recommend a captcha security system as the attacker could simply switch to another annoying word.
Goatse's arn't your problem here, it's the security.
You can use stristr http://php.net/manual/de/function.stristr.php to achive this. I would recommend to using a captcha, since it is more efficient. A popular solution is reCaptcha: https://developers.google.com/recaptcha/docs/php Another, weaker possibility is to add a security question to your form, for instance "What is five plus five in numbers?".
Try the following:
function is_spam($array, $block_pattern){
$block = false;
foreach($array as $k => $v){
if(preg_match('/.*' . $block_pattern . '.*/', $k) ||
preg_match('/.*' . $block_pattern . '.*/', $v)){
$block = true;
break;
}
}
return $block;
}
Usage: is_spam($_POST, 'goatse');
Returns: true if 'goatse' is found in $_POST
The function will search all keys and values of $array for the $block_pattern string and will return true if the pattern is found.
I am trying to fetch a mail from POP3 (I am using POP3 mail server and I am trying to fetch the mail content and store into a database table for my project.), but I can't find any PHP script for that, all are only for IMAP.
Do you know how to fetch mail from a POP3 server?
Thanks.
Somewhat surprisingly, PHP's imap library can be also used for working with POP3 mailboxes. Most of the advanced IMAP features won't work, of course (e.g. folders or fetching message parts), but the basic POP3 functionality is implemented.
The main difference is the option string that you're passing to imap_open - to quote that page:
// To connect to a POP3 server on port 110 on the local server, use:
$mbox = imap_open ("{localhost:110/pop3}INBOX", "user_id", "password");
Other than that, it's fair sailing - you won't need more than imap_open, imap_num_msg, imap_body, imap_delete and imap_close for basic POP3 access.
PHP's IMAP functions can deal with both IMAP and POP3 boxes.
These functions enable you to operate with the IMAP protocol, as well as the NNTP, POP3 and local mailbox access methods.
Be warned, however, that some IMAP functions will not work correctly with the POP protocol.
there is a User Contributed Note that provides an interesting snippet. You may want to take a look at it. I can't say anything about its quality but from the surface, it looks okay.
Below, the Contributed Note:
For all the people coming here praying for:
1) a dead-easy way to read MIME attachments, or
2) a dead-easy way to access POP3 folders
Look no further.
function pop3_login($host,$port,$user,$pass,$folder="INBOX",$ssl=false)
{
$ssl=($ssl==false)?"/novalidate-cert":"";
return (imap_open("{"."$host:$port/pop3$ssl"."}$folder",$user,$pass));
}
function pop3_stat($connection)
{
$check = imap_mailboxmsginfo($connection);
return ((array)$check);
}
function pop3_list($connection,$message="")
{
if ($message)
{
$range=$message;
} else {
$MC = imap_check($connection);
$range = "1:".$MC->Nmsgs;
}
$response = imap_fetch_overview($connection,$range);
foreach ($response as $msg) $result[$msg->msgno]=(array)$msg;
return $result;
}
function pop3_retr($connection,$message)
{
return(imap_fetchheader($connection,$message,FT_PREFETCHTEXT));
}
function pop3_dele($connection,$message)
{
return(imap_delete($connection,$message));
}
function mail_parse_headers($headers)
{
$headers=preg_replace('/\r\n\s+/m', '',$headers);
preg_match_all('/([^: ]+): (.+?(?:\r\n\s(?:.+?))*)?\r\n/m', $headers, $matches);
foreach ($matches[1] as $key =>$value) $result[$value]=$matches[2][$key];
return($result);
}
function mail_mime_to_array($imap,$mid,$parse_headers=false)
{
$mail = imap_fetchstructure($imap,$mid);
$mail = mail_get_parts($imap,$mid,$mail,0);
if ($parse_headers) $mail[0]["parsed"]=mail_parse_headers($mail[0]["data"]);
return($mail);
}
function mail_get_parts($imap,$mid,$part,$prefix)
{
$attachments=array();
$attachments[$prefix]=mail_decode_part($imap,$mid,$part,$prefix);
if (isset($part->parts)) // multipart
{
$prefix = ($prefix == "0")?"":"$prefix.";
foreach ($part->parts as $number=>$subpart)
$attachments=array_merge($attachments, mail_get_parts($imap,$mid,$subpart,$prefix.($number+1)));
}
return $attachments;
}
function mail_decode_part($connection,$message_number,$part,$prefix)
{
$attachment = array();
if($part->ifdparameters) {
foreach($part->dparameters as $object) {
$attachment[strtolower($object->attribute)]=$object->value;
if(strtolower($object->attribute) == 'filename') {
$attachment['is_attachment'] = true;
$attachment['filename'] = $object->value;
}
}
}
if($part->ifparameters) {
foreach($part->parameters as $object) {
$attachment[strtolower($object->attribute)]=$object->value;
if(strtolower($object->attribute) == 'name') {
$attachment['is_attachment'] = true;
$attachment['name'] = $object->value;
}
}
}
$attachment['data'] = imap_fetchbody($connection, $message_number, $prefix);
if($part->encoding == 3) { // 3 = BASE64
$attachment['data'] = base64_decode($attachment['data']);
}
elseif($part->encoding == 4) { // 4 = QUOTED-PRINTABLE
$attachment['data'] = quoted_printable_decode($attachment['data']);
}
return($attachment);
}
you can use pop3 e-mail client class which can Access to e-mail mailboxes using the POP3 protocol.
You will get each e-mail body part and can store it in database, even you can retrieve attached files without deleting the original mail in the inbox.
For more go to http://www.phpclasses.org/package/2-PHP-Access-to-e-mail-mailboxes-using-the-POP3-protocol.html
IF you have PHP build with IMAP support, it would be easy, see IMAP documentation (especially comments at this page) at http://php.net/manual/en/book.imap.php
UPDATE: to clarify my answer - as you see in the comments and function reference, PHP imap_* functions can be used also for pop3.
You can open a socket connection and send POP3 commands directly to your server to retrieve emails.
The code below opens a connection to the server, authenticates, requests a count of available messages, downloads them one by one, then deletes them from the server. During the interaction with the server, if an unexpected response is received, the connection is closed.
You should be able to alter the code below to get what you need.
Create a config.ini file and populate it like this:
pop3_host=your.pop3.host
pop3_user=youremailusername
pop3_pass=youremailpassword
Obviously substitute the values with your actual host, username and password. Then change the parse_ini_file parameter to point to your config.ini file.
<?php
$config = parse_ini_file('/path/to/config.ini');
$stream = fsockopen('ssl://' . $config['pop3_host'], 995, $error_code, $error_message);
if (!$stream) {
die('fsockopen ' . $error_code . ' ' . $error_message);
}
$s = fgets($stream);
if (substr($s, 0, 3) !== '+OK') {
quit('OPEN');
}
chat('USER ' . $config['pop3_user']);
chat('PASS ' . $config['pop3_pass']);
$s = chat('STAT');
$stat = explode(' ', $s);
if (count($stat) !== 3) {
quit('STAT+');
}
$n = (integer)$stat[1];
for ($i = 1; $i <= $n; $i++) {
chat('RETR ' . $i);
$file = fopen($i . '.msg', 'wb');
if (!$file) {
quit('FILE ' . $i);
}
while (true) {
$s = fgets($stream);
if ($s === '.' . "\r\n") {
fclose($file);
break;
}
fputs($file, $s);
}
chat('DELE ' . $i);
}
chat('QUIT');
fclose($stream);
function chat(string $command): string {
global $stream;
fputs($stream, $command . "\r\n");
$s = fgets($stream);
if (substr($s, 0, 3) !== '+OK') {
quit(explode(' ', $command)[0]);
}
return $s;
}
function quit(string $message): void {
global $stream;
fputs($stream, 'QUIT' . "\r\n");
$s = fgets($stream);
fclose($stream);
die($message);
}
I need to create a PHP class that would send e-mails to all members of the website. Simple mysql_fetch_array and loop doesn't fit because my client wants a class and I actually don't know much about classes and what he exactly wants. Can you explain or give me any hints?
Well in general, we can't tell you what your client wants. You'll have to ask him. :) But a few general pointers on sending out bigger numbers of E-Mails.
When putting together an E-Mail class, the most sensitive thing to be aware of, and the most likely reason for it not working, is the number of mails to be sent. mail() is a very slow command for sending mails, and if you have thousands of members, a pure mail() solution is likely to fail, because the run time of a PHP script is usually limited to 30 or 60 seconds.
Check out E-Mailing classes like PHPMailer that can send directly through SMTP, which is way faster.
Also be sure to check out whether the server the mails are sent from has any limit imposed on the number of outgoing E-Mails per interval. If you are using a hosting provider, talk to them first. This is also good because then they know you're not misusing their servers for spam.
Be sure to do test runs before actually starting the sending out to actual members.
Also make sure your outgoing E-Mails look o.k. technically so they don't get spam filtered. See this question for a few pointers.
For basics on Object Oriented Programming, see e.g. the PHP Manual on the subject.
Generally, be very careful when working on a mailing system. Make sure you have checks in place that prevent actual sending to actual members before everything is in order. Imagine how embarrassing it is to have ten "asfsafsd" test E-Mails sent out to each person on the recipient list.
Don't forget that there are paid services available that do this as well. If there is some budget involved, and you would like to use an existing paid solution rather than do it yourself, you can set up another question here on SO.
Well first you should ask your client what he wants if you don't know it. Otherwise you can't proceed. Second, make yourself familiar with Object Oriented Programming especially in PHP.
if can use phpmailer is a class that handle all mail send,
or use a class from phpclasess site (required register)
http://www.phpclasses.org/browse/package/1553.html
the class code :
<?
/* sendMail Class - by André Cupini - andre#neobiz.com.br */
class sendMail
{
var $to;
var $cc;
var $bcc;
var $subject;
var $from;
var $headers;
var $html;
function sendMail()
{
$this->to = NULL;
$this->cc = NULL;
$this->bcc = NULL;
$this->subject = NULL;
$this->from = NULL;
$this->headers = NULL;
$this->html = FALSE;
}
function getParams($params)
{
$i = 0;
foreach ($params as $key => $value) {
switch($key) {
case 'to':
$this->to = $value;
break;
case 'cc':
$this->cc = $value;
break;
case 'bcc':
$this->bcc = $value;
break;
case 'subject':
$this->subject = $value;
break;
case 'from':
$this->from = $value;
break;
case 'submitted':
NULL;
break;
default:
$this->body[$i]["key"] = str_replace("_", " ", ucWords(strToLower($key)));
$this->body[$i++]["value"] = $value;
}
}
}
function setHeaders()
{
$this->headers = "From: $this->from\r\n";
if($this->html === TRUE) {
$this->headers.= "MIME-Version: 1.0\r\n";
$this->headers.= "Content-type: text/html; charset=iso-8859-1\r\n";
}
if(!empty($this->cc)) $this->headers.= "Cc: $this->cc\r\n";
if(!empty($this->bcc)) $this->headers.= "Bcc: $this->bcc\r\n";
}
function parseBody()
{
$count = count($this->body);
for($i = 0; $i < $count; $i++) {
if($this->html) $content.= "<b>";
$content .= $this->body[$i]["key"].': ';
if($this->html) $content.= "</b>";
if($this->html) $content .= nl2br($this->body[$i]["value"])."\n";
else $content .= $this->body[$i]["value"];
if($this->html) $content.= "<hr noshade size=1>\n";
else $content.= "\n".str_repeat("-", 80)."\n";
}
if($this->html) {
$content = "
<style>
BODY {
font-family: verdana;
font-size: 10;
}
</style>
".$content;
}
$this->body = $content;
}
function send()
{
if(mail($this->to, $this->subject, $this->body, $this->headers)) return TRUE;
else return FALSE;
}
function set($key, $value)
{
if($value) $this->$key = $value;
else unset($this->$key);
}
}
?>
Having a class is a pretty vague requirement, as you could simply wrap your code into a Class like this:
class Mailer
{
public function sendMail()
{
// $users = mysql_fetch_array()
// loop $users
// mail($user)
}
}
Requirement met. Granted, it's a bad class and it's likely not, what your client had in mind. I suggest to ask your client to be more specific about the requirements or what he is looking for the class to do exactly and what level of abstraction and flexibility he seeks.
Then again, there is no need to reinvent classes that can send eMail, when there is a plethora readily available. Two very flexible being Zend_Mail and PEAR Mail.
Yup, all above answers are true. I use PHP Mailer all of the time. I personally have an "outbox" table in my database where I queue outgoing messages. Then I have a CRON job go through and send chunks out at a time. Not only does this give you the control over your rate of sending but if you "mess up" and send something wrong, you can quickly go into the database and clear them all out before the cron comes around. I've even implemented priorities in my bigger projects so that important emails will go out before things like a newsletter.
Good Luck!