Is this a safe PHP mail function? - php

I've finally got this PHP email script working (didn't work on localhost…), but my concern is that it's not safe.
So - is this safe for spamming and any other security pitfalls I'm not aware of?
<?php
$email = 'notification#domain.com';
$subject = 'Notify about stuff';
$notify = $_REQUEST['email'];
if (!preg_match("/\w+([-+.]\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*/", $notify)) {
echo "<h4>Your email address doesn't validate, please check that you typed it correct.</h4>";
echo "<a href='javascript:history.back(1);'>Back</a>";
}
elseif(mail($email, $subject, $notify)) {
echo "<h4>Thank you, you will be notified.</h4>";
} else {
echo "<h4>Sorry, your email didn't get registered.</h4>";
}
?>
Unrelated: is there a PHP function I can use instead of javascript:history.back(1) ?
Edit: the script using filter instead of RegEx
<?php
$email = 'notification#domain.com';
$subject = 'Notify about stuff';
$notify = $_REQUEST['email'];
if (!filter_var($notify, FILTER_VALIDATE_EMAIL)) {
echo "<h4>This email address ($notify) is not considered valid, please check that you typed it correct.</h4>";
echo "<a href='javascript:history.back(1);'>Back</a>";
}
elseif(mail($email, $subject, $notify)) {
echo "<h4>Thank you, you will be notified.</h4>";
} else {
echo "<h4>Sorry, your email didn't get registered.</h4>";
}
?>

I don't know if id use $_SERVER['HTTP_REFERER'] to go back. I feel like that could leave you open to attack since it's set via the request. The way to do it would be to use sessions on the previous page. This way you're not dumping untrustworthy data onto your site.
I dont see any security risks, but id like to suggest the use of filter when checking the validity of emails. its much easier than messing with REs.

You can't just regexp match an email address against a short regexp pattern if you want to accept all validly formed email addresses and reject all non-valid one. Use a parser (1, 2) that actually implement against the relevant RFCs to check for validity.
Other things you can do is checking HTTP_REFERER to make sure the request came from within your domain as Chacha102 already mentioned. Just note that not all agent send HTTP_REFERER, and that it can be optionally turned off or faked by users.
If you want to go the extra mile to make sure they are giving you a valid email address, you can check for existing DNS record for mail servers at the domain specified (A, MX, or AAAA). And on top of that, you can do callback verification. That's where you connect to the mail server, tell it you want to send to this email address and see if they say OK.
For callback verification, you should note greylisting servers say OK to everything so even that is not a guarantee. Here's some code I used when I needed such a script. It's a patch onto the parser from (1).
#
# Email callback verification
# Based on http://uk2.php.net/manual/en/function.getmxrr.php
#
if (strlen($bits['domain-literal'])){
$records = array($bits['domain-literal']);
}elseif (!getmxrr($bits['domain'], $mx_records, $mx_weight)){
$records = array($bits['domain']);
}else{
$mxs = array();
for ($i = 0; $i < count($mx_records); $i++){
$mxs[$mx_records[$i]] = $mx_weight[$i];
}
asort($mxs);
$records = array_keys($mxs);
}
$user_okay = false;
for ($j = 0; $j < count($records) && !$user_okay; $j++){
$fp = #fsockopen($records[$j], 25, $errno, $errstr, 2);
if($fp){
$ms_resp = "";
$ms_resp .= send_command($fp, "HELO ******.com");
$ms_resp .= send_command($fp, "MAIL FROM:<>");
$rcpt_text = send_command($fp, "RCPT TO:<" . $email . ">");
$ms_resp .= $rcpt_text;
$ms_code = intval(substr($rcpt_text, 0, 3));
if ($ms_code == 250 || $ms_code == 451){ // Accept all user account on greylisting server
$user_okay = true;
}
$ms_resp .= send_command($fp, "QUIT");
fclose($fp);
}
}
return $user_okay ? 1 : 0;

Related

PHP - Verifying emails existance [duplicate]

I have a question, i have a php script to check if the email address exist.
But appear that yahoo, hotmail, aol and others providers are accepting any emails and not rejecting the invalid emails.
Only Gmail, and many domains like stackoverflow.com are rejecting the no vaild emails.
Check my script and let me know if i can do some to check the yahoo and others.
html post form
<html>
<body>
<form action="checkemail.php" method="POST">
<b>E-mail</b> <input type="text" name="email">
<input type="submit">
</form>
</body>
</html>
php
<?php
/* Validate an email address. */
function jValidateEmailUsingSMTP($sToEmail, $sFromDomain = "gmail.com", $sFromEmail = "email#gmail.com", $bIsDebug = false) {
$bIsValid = true; // assume the address is valid by default..
$aEmailParts = explode("#", $sToEmail); // extract the user/domain..
getmxrr($aEmailParts[1], $aMatches); // get the mx records..
if (sizeof($aMatches) == 0) {
return false; // no mx records..
}
foreach ($aMatches as $oValue) {
if ($bIsValid && !isset($sResponseCode)) {
// open the connection..
$oConnection = #fsockopen($oValue, 25, $errno, $errstr, 30);
$oResponse = #fgets($oConnection);
if (!$oConnection) {
$aConnectionLog['Connection'] = "ERROR";
$aConnectionLog['ConnectionResponse'] = $errstr;
$bIsValid = false; // unable to connect..
} else {
$aConnectionLog['Connection'] = "SUCCESS";
$aConnectionLog['ConnectionResponse'] = $errstr;
$bIsValid = true; // so far so good..
}
if (!$bIsValid) {
if ($bIsDebug) print_r($aConnectionLog);
return false;
}
// say hello to the server..
fputs($oConnection, "HELO $sFromDomain\r\n");
$oResponse = fgets($oConnection);
$aConnectionLog['HELO'] = $oResponse;
// send the email from..
fputs($oConnection, "MAIL FROM: <$sFromEmail>\r\n");
$oResponse = fgets($oConnection);
$aConnectionLog['MailFromResponse'] = $oResponse;
// send the email to..
fputs($oConnection, "RCPT TO: <$sToEmail>\r\n");
$oResponse = fgets($oConnection);
$aConnectionLog['MailToResponse'] = $oResponse;
// get the response code..
$sResponseCode = substr($aConnectionLog['MailToResponse'], 0, 3);
$sBaseResponseCode = substr($sResponseCode, 0, 1);
// say goodbye..
fputs($oConnection,"QUIT\r\n");
$oResponse = fgets($oConnection);
// get the quit code and response..
$aConnectionLog['QuitResponse'] = $oResponse;
$aConnectionLog['QuitCode'] = substr($oResponse, 0, 3);
if ($sBaseResponseCode == "5") {
$bIsValid = false; // the address is not valid..
}
// close the connection..
#fclose($oConnection);
}
}
if ($bIsDebug) {
print_r($aConnectionLog); // output debug info..
}
return $bIsValid;
}
$email = $_POST['email'];
$bIsEmailValid = jValidateEmailUsingSMTP("$email", "gmail.com", "email#gmail.com");
echo $bIsEmailValid ? "<b>Valid!</b>" : "Invalid! :(";
?>
If you need to make super sure that an E-Mail address exists, send an E-Mail to it. It should contain a link with a random ID. Only when that link is clicked, and contains the correct random ID, the user's account is activated (or ad published, or order sent, or whatever it is that you are doing).
This is the only reliable way to verify the existence of an E-Mail address, and to make sure that the person filling in the form has access to it.
There is no 100% reliable way of checking the validity of an email address. There are a few things you can do to at least weed out obviously invalid addresses, though.
The problems that arise with email addresses is actually very similar to those of snail mail. All three points below can also be used for sending snail mail (just change the DNS record with a physical address).
1. Check that the address is formatted correctly
It is very difficult to check the format of email addresses, but PHP has a validation filter that attempts to do it. The filter does not handle "comments and folding whitespace", but I doubt anyone will notice.
if (filter_var($email, FILTER_VALIDATE_EMAIL) !== FALSE) {
echo 'Valid email address formatting!';
}
2. Check that the DNS record exists for the domain name
If a DNS (Domain Name System) record exists then at least someone has set it up. It does not mean that there is an email server at the address, but if the address exists then it is more likely.
$domain = substr($email, strpos($email, '#') + 1);
if (checkdnsrr($domain) !== FALSE) {
echo 'Domain is valid!';
}
3. Send a verification email to the address
This is the most effective way of seeing if someone is at the other end of the email address. If a confirmation email is not responded to in an orderly fashion -- 3 hours for example -- then there is probably some problem with the address.
You can validate "used or real" emails with Telnet and MX records more info in here, for PHP exists a great library call php-smtp-email-validation that simplify the process.
You create a boolean function with the file example1.php and call it when you'll validate the email text. For Gmail, Hotmail, Outlook, live and MSM I don's have any problems but with Yahoo and Terra the library can't validate correctly emails
The problem is gmail uses port 25 for their smtp outgoing mails, the other providers use different ports for their connection. Your response seems okay for gmail.com.
When you connect to gmail smtp it gives you response 250 2.1.5 OK j5si2542844pbs.271 - gsmtp
But when you connect to any other smtp who does not use port 25 it gives you null response.

Bann one or more IP address with PHP withouthtaccess using .htaccess

I'm looking for good code in PHP for Banning some spammers IP's My server is giving me error 500 if I'm using .htaccess
This will do the work
$getip = $_SERVER["REMOTE_ADDR"];
$banned_ip = array();
$banned_ip[] = '194.9.94.*';
$banned_ip[] = '77.105.2.*';
foreach($banned_ip as $banned)
{
$blacked=str_replace('*', '', $banned);
$len=strlen($blacked);
if ($getip==$blacked || substr($getip, 0, $len)==$blacked)
{
$_banned_ip=true;
}
}
if($_banned_ip==true){
echo 'THIS IP IS BANNED!';
exit;
}
The simplest way would be to have a database that keeps a list of the banned ip addresses, if you want to do it on the PHP end rather than directly in the server.
for($i = 0;$i < count($listOfIps);$i++) {
if($listOfIps[$i] == filteredIP($_SERVER['REMOTED_ADDR'])) { //filteredIP is not a native function, it's just a representation of however you want to filter the ip addresses which are sent to you
$banned = true;
}
}
if($banned):
//redirect user or kill script
else:
//render page
endif;
However, there may be better solutions based on the page or application specifics, but this is the best solution I can think of based on your question

PHP return false if certain word appears in $_POST[xxx]

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.

PHPList fails for email addresses with leading, trailing, or multiple adjacent dots

PHPList (version 2.10.17) fails to send messages to addresses that match one of the following formats:
my..Name#domain.com
myName.#domain.com
.myName#domain.com
the error message is Could not instantiate mail function.
The code in question is:
function MailSend($header, $body) {
$to = "";
for($i = 0; $i < count($this->to); $i++)
{
if($i != 0) { $to .= ", "; }
$to .= $this->to[$i][0];
}
if ($this->Sender != "" && (bool) ini_get("safe_mode") === FALSE)
{
$old_from = ini_get("sendmail_from");
ini_set("sendmail_from", $this->Sender);
$params = sprintf("-oi -f %s", $this->Sender);
$rt = #mail($to, $this->EncodeHeader($this->Subject), $body,
$header, $params);
}
else
$rt = #mail($to, $this->EncodeHeader($this->Subject), $body, $header);
if (isset($old_from))
ini_set("sendmail_from", $old_from);
if(!$rt)
{
$this->SetError($this->Lang("instantiate"));
return false;
}
return true;
}
The chosen code path is:
else
$rt = #mail($to, $this->EncodeHeader($this->Subject), $body, $header);
I could not reproduce this error on my own webserver where I set up PHPList for testing purposes.
Unfortunately the only system that is showing this behaviour is the production system. To add to that, I don't have access to any logfiles on that system - so I don't really know what is wrong.
My best guess is, that some sort of "string escape" on $to is needed to make this work, but I am somewhat reluctant to tamper with a production system (other than inserting some logging output).
Does anyone know a workaround for this sort of problem?
This is not an error, it is expected behavior. The local-part of an email address (the part before the #) may contain ., provided it is not the first nor the last character, and provided also that it does not appear two or more times consecutively. This means all three examples are invalid email addresses.
Read more about valid email addresses.

Best email validation function in general and specific (college domain)?

I know email validation is one of those things which is not the funniest thing on the block. I'm starting up a website and i want to limit my audience to only the people in my college and i also want a preferred email address for my user. So this is a two part question.
Is there a really solid php function out there for email validation?
Can I validate an email from a specific domain. I dont want to just check if the domain exists, because I know www.mycollege.edu exists already. Is there really anyway to validate that the user has a valid #mycollege.edu web address?
This is what I use:
function check_email_address($email) {
// First, we check that there's one # symbol, and that the lengths are right
if (!preg_match("/^[^#]{1,64}#[^#]{1,255}$/", $email)) {
// Email invalid because wrong number of characters in one section, or wrong number of # symbols.
return false;
}
// Split it into sections to make life easier
$email_array = explode("#", $email);
$local_array = explode(".", $email_array[0]);
for ($i = 0; $i < sizeof($local_array); $i++) {
if (!preg_match("/^(([A-Za-z0-9!#$%&'*+\/=?^_`{|}~-][A-Za-z0-9!#$%&'*+\/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$/", $local_array[$i])) {
return false;
}
}
if (!preg_match("/^\[?[0-9\.]+\]?$/", $email_array[1])) { // Check if domain is IP. If not, it should be valid domain name
$domain_array = explode(".", $email_array[1]);
if (sizeof($domain_array) < 2) {
return false; // Not enough parts to domain
}
for ($i = 0; $i < sizeof($domain_array); $i++) {
if (!preg_match("/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$/", $domain_array[$i])) {
return false;
}
}
}
return true;
}
EDIT Replaced depreciated ereg with preg_match for PHP 5.3 compliance
If you really want to make sure its valid make your signup form send them an email with a URL link in that they have to click to validate.
This way not only do you know the address is valid (because the received the email), but you also know the owner of the account has signed up (unless someone else knows his login details).
To make sure it ends correctly you could use explode() on the '#' and check the second part.
$arr = explode('#', $email_address);
if ($arr[1] == 'mycollege.edu')
{
// Then it's from your college
}
PHP also has it's own way of validating email addresses using filter_var: http://www.w3schools.com/php/filter_validate_email.asp
This should work:
if (preg_match('/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])#mycollege.edu$/', $email)) {
// Valid
}
Read here
http://ru2.php.net/manual/en/book.filter.php
Or in short
var_dump(filter_var('bob#example.com', FILTER_VALIDATE_EMAIL));
this might be a better solution. many answered already, eventhough its little different.
$email = "info#stakoverflow.com";
if (!filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
echo $email ." is a valid email address";
} else {
echo $email ." is not a valid email address";
}
I hope this one has simple to use.
for any e-mail
([a-zA-Z0-9_-]+)(\#)([a-zA-Z0-9_-]+)(\.)([a-zA-Z0-9]{2,4})(\.[a-zA-Z0-9]{2,4})?
for php preg_match function
/([a-zA-Z0-9_-]+)(\#)([a-zA-Z0-9_-]+)(\.)([a-zA-Z0-9]{2,4})(\.[a-zA-Z0-9]{2,4})?/i
for #mycollege.edu
^([a-zA-Z0-9_-]+)(#mycollege.edu)$
for php preg_match function
/^([a-zA-Z0-9_-]+)(#mycollege.edu)$/i
PHP CODE
<?php
$email = 'tahir_aS-adov#mycollege.edu';
preg_match('/^([a-zA-Z0-9_-]+)(#mycollege.edu)$/i', $email, $matches);
if ($matches) {
echo "Matched";
} else {
echo "Not Matched";
}
var_dump($matches);
A simple function using filter_var in php
<?php
function email_validation($email) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
echo("$email is a valid email address");
} else {
echo("$email is not a valid email address");
}
}
//Test
email_validation('johnson123');
?>

Categories