Please review my mail script
Posted: Tue Sep 23, 2008 3:14 pm
Hello,
I've written a php script that can send mails. It's mainly for myself when I want to quickly send mails and don't have my mail client at hand. Security holes in this script are obviously an invitation to spammer therefore I would be glad if you could look over it and tell me if you spot something I missed.
The password is mymail. If the script goes life I'll change it to something more secure.
I've written a php script that can send mails. It's mainly for myself when I want to quickly send mails and don't have my mail client at hand. Security holes in this script are obviously an invitation to spammer therefore I would be glad if you could look over it and tell me if you spot something I missed.
The password is mymail. If the script goes life I'll change it to something more secure.
Code: Select all
<?php
// Configuration constants
define("PW_MD5", "061b876db2ac78e2473150f959cb7ae3");
define("THIS_FILE", $_SERVER['PHP_SELF']);
define("USER_EMAIL", "foo@bar.net");
define("BLIND_COPY_EMAIL", "blindcopy@bar.net");
define("USER_NAME", "Me");
sleep(1);
// Helper Functions
function is_valid_address($email){
return
// foo@bar.tdl
preg_match("/^[^@]+\\@.{3,}\\.[a-zA-Z]{2,}$/", $email) == 1 ||
// Name <foo@bar.tdl>
preg_match("/^.+<[^@]+\\@.{3,}\\.[a-zA-Z]{2,}>$/", $email) == 1
;
}
function escape_quotes($str){
return str_replace("\"","\\\"", $str);
}
function is_space_string($str){
return preg_match("/^\\s*$/", $str);
}
function constains_newlines($str){
return strpos($str, "\n") !== false;
}
// Test config values
if(!is_valid_address(USER_EMAIL))
die("USER_EMAIL=".USER_EMAIL." is invalid");
// Default values
$pw = "";
$to = "";
$cc = array();
$from = USER_NAME." <".USER_EMAIL.">";
$reply_to = USER_NAME." <".USER_EMAIL.">";
$copy_to_sender = true;
$title = "";
$body = "";
$error_msg = array();
$notice_msg = array();
// Load POST input
$input_complete = false;
if(array_key_exists("send_email", $_POST)){
$input_complete = true;
if(array_key_exists("pw", $_POST))
$pw = $_POST["pw"];
else
$input_complete = false;
if(array_key_exists("to", $_POST))
$to = $_POST["to"];
else
$input_complete = false;
if(array_key_exists("cc", $_POST)){
$cc = array();
foreach(explode("\n", str_replace("\r\n", "\n", $_POST["cc"])) as $email)
if(!is_space_string($email))
$cc[] = $email;
}else
$input_complete = false;
if(array_key_exists("from", $_POST))
$from = $_POST["from"];
else
$input_complete = false;
if(array_key_exists("reply_to", $_POST))
$reply_to = $_POST["reply_to"];
else
$input_complete = false;
if(array_key_exists("title", $_POST))
$title = $_POST["title"];
else
$input_complete = false;
if(array_key_exists("body", $_POST))
$body = $_POST["body"];
else
$input_complete = false;
if(array_key_exists("copy_to_sender", $_POST))
$copy_to_sender = true;
else{
// A missing copy_to_sender can mean that the checkbox
// is unchecked or that the information was never send by
// the browser. :/
//
// Workaround: If all input was complete so far then it
// was most likely not set.
if($input_complete)
$copy_to_sender = false;
}
if(!$input_complete)
$error_msg[] = "Post data was incomplete (This error should not show in normal usage scenarios.)";
}
// Check input validity
$input_valid = false;
if($input_complete){
$input_valid = true;
if(md5($pw) != PW_MD5){
$error_msg[] = "Wrong password";
$input_valid = false;
}
function format_ith($i){
if(10 <= $i && $i < 20)
return $i."th";
if(100 <= $i || $i <= 0)
return $i."th";
switch($i % 10){
case 1:return $i."st";
case 2:return $i."nd";
case 3:return $i."rd";
default:return $i."th";
}
}
for($i = 0; $i < count($cc); ++$i)
if(!is_valid_address($cc[$i]) || constains_newlines($cc[$i])){
$input_valid = false;
$error_msg[] = format_ith($i+1)." cc-email invalid";
}
if(!is_valid_address($to) || constains_newlines($to)){
$input_valid = false;
$error_msg[] = "to-email invalid";
}
if(!is_valid_address($from) || constains_newlines($from)){
$input_valid = false;
$error_msg[] = "from-email invalid";
}
if(!is_valid_address($reply_to) || constains_newlines($reply_to)){
$input_valid = false;
$error_msg[] = "reply-to-email invalid";
}
if(count($to) == 0){
$input_valid = false;
$error_msg[] = "no to-email";
}
if(is_space_string($title)){
$input_valid = false;
$error_msg[] = "no title";
}else if(constains_newlines($title)){
$input_valid = false;
$error_msg[] = "title mustn't contain newlines";
}
if(is_space_string($body)){
$input_valid = false;
$error_msg[] = "no body";
}
// Make sure all newlines are of the style \r\n
$body = str_replace("\r\n", "\n", $body);
$body = str_replace("\n", "\r\n", $body);
}
// Send Mail
if($input_complete && $input_valid){
if($copy_to_sender){
$subject = "This mail was sent to: $to \r\n";
if(count($cc)){
$subject .= "\r\n".
"This mail was also cc-ed to:\r\n".
"\r\n";
foreach($cc as $email)
$subject .= '- '. $email . "\r\n";
}
$subject .= "\r\n".
"The content of the original mail was:\r\n".
"------------------------------------ \r\n".
$body;
$header = 'From: ' . BLIND_COPY_EMAIL . "\r\n";
if(@mail(USER_EMAIL, 'blind copy:'.$title, $subject, $header))
$notice_msg[] = 'blind copy sent to '.USER_EMAIL;
else
$error_msg[] = 'could not send blind copy to '.USER_EMAIL;
}
$header = 'From: ' . $from . "\r\n";
if($from != $reply_to)
$header .= 'Reply-to: ' . $reply_to . "\r\n";
foreach($cc as $email)
$header .= 'Cc: '. $email . "\r\n";
if(@mail($to, $title, $body, $header))
$notice_msg[] = 'e-mail was sent';
else
$error_msg[] = 'could not send e-mail';
}
// Send form
?>
<html>
<head>
<title>Send E-Mails from <?php echo USER_EMAIL ?></title>
</head>
<body>
<?php
if(count($error_msg) != 0){
if(count($error_msg) == 1)
echo "\t\t<h1>Error occured</h1>\n";
else
echo "\t\t<h1>Errors occured</h1>\n";
echo "\t\t<ul>\n";
foreach($error_msg as $msg)
echo "\t\t\t<li>".$msg."</li>\n";
echo "\t\t</ul>\n";
}
if(count($notice_msg) != 0){
if(count($notice_msg) == 1)
echo "\t\t<h1>Notice was raised</h1>\n";
else
echo "\t\t<h1>Notices were raised</h1>\n";
echo "\t\t<ul>\n";
foreach($notice_msg as $msg)
echo "\t\t\t<li>".$msg."</li>\n";
echo "\t\t</ul>\n";
}
?> <form action="<?php echo THIS_FILE ?>" method="post">
<p>
<input type="submit" value="Send E-Mail" />
<input type="hidden" name="send_email" value="do"/>
<a href="<?php echo THIS_FILE?>">New mail</a>
</p>
<table border="0">
<tr>
<td>
Password:
</td>
<td>
<input style="font-family:monospace" size="70" name="pw" type="password"/>
</td>
</tr>
<tr>
<td>
To:
</td>
<td>
<input style="font-family:monospace" size="70" name="to" type="text" value="<?php echo escape_quotes($to)?>"/>
</td>
</tr>
<tr>
<td>
CC:
</td>
<td>
<textarea style="font-family:monospace" cols="70" name="cc" rows="5"><?php echo htmlspecialchars(implode("\n", $cc))?></textarea>
</td>
</tr>
<tr>
<td>
From:
</td>
<td>
<input style="font-family:monospace" size="70" name="from" type="text" value="<?php echo escape_quotes($from)?>"/>
</td>
</tr>
<tr>
<td>
Reply-To:
</td>
<td>
<input style="font-family:monospace"size="70" name="reply_to" type="text" value="<?php echo escape_quotes($reply_to)?>"/>
</td>
</tr>
<tr>
<td>
<input type="checkbox" name="copy_to_sender" value="on" <?php if($copy_to_sender)echo "checked"?>>
</td>
<td>
Send blind copy to <?php echo USER_EMAIL?>
</td>
</tr>
<tr>
<td>
Title:
</td>
<td>
<input style="font-family:monospace"size="70" name="title" type="text" value="<?php echo escape_quotes($title)?>"/>
</td>
</tr>
</table>
<p>
<textarea style="font-family:monospace" name="body" cols="100" rows="50"><?php echo htmlspecialchars($body)?></textarea>
</p>
<p>
<input type="submit" value="Send E-Mail" />
<a href="<?php echo THIS_FILE?>">New mail</a>
</p>
</form>
</body>
</html>