0

I am in the process of building my contact forms email address validation script. Having debugged it and run basic test's using valid email addresses which all passed I went on to test for invalid addresses. My first test was .ala.dom.com which is a clear invalid with both starting and ending dots. I expected to get my error message thrown up. However; my host has set the magic_quotes on and instead the email went through because the escaped the whole local part of the address with " like this ".ala."@dom.com

This is an excert of the actual header that arrived in the email inbox -

Received: by srv28.000webhost.com (Postfix, from userid 7695918)
    id 899601EE9C2; Sat, 5 Oct 2013 16:21:37 -0400 (EDT)
To: net@weedy101.netii.net
Subject: Should fold
X-PHP-Script: weedy101.netii.net/new-mail.php for 2.26.7.205
From: ".ala."@dom.com
Reply-To: ".ala."@dom.com
Content-type: text/html
Message-Id: <20131005202137.899601EE9C2@srv28.000webhost.com>
Date: Sat, 5 Oct 2013 16:21:37 -0400 (EDT)

My host's are 000webhosts.com with a free account so even though they are only using php 5.2.* I can't access the php.ini to change the setting so therefore I need to programtically strip the inserted characters, or find another work around. I am totally stumped as to how best to handle this problem. My validation script is -

<?php
if (isset($_POST['name']) && isset($_POST['message']) && isset($_POST['email']) && isset($_POST['subject'])) {

    $name = $_POST['name'];
    $text = $_POST['message'];
    $contact = $_POST['email'];
    $subject = $_POST['subject'];
    $isValid = true;
    $atIndex = strrpos($contact, "@");
    $problem = 1;

    if (is_bool($atIndex) && !$atIndex) {

        $isValid = false;
        $problem = 2;

    }
    else {

        $domain = substr($contact, $atIndex+1);
        $local = substr($contact, 0, $atIndex);
        $localLen = strlen($local);
        $domainLen = strlen($domain);

        if ($localLen < 1 || $localLen > 64) {

            $isValid = false;
            $problem = 3;

        }
        else if ($domainLen < 1 || $domainLen > 255) {

            $isValid = false;
            $problem = 4;

        }
        else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) {

            $isValid = false;
            $problem = 5;

        }
        else if (preg_match('/\\.\\./', $domain)) {

            $isValid = false;
            $problem = 6;

        }
        else if (!(checkdnsrr($domain,"MX") || checkdnsrr($domain, "A"))) {

            $isValid = false;
            $problem = 7;

        }
        else if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%£`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\","",$local))) {

            if (!preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\","",$local))) {

                $isValid = false;
                $problem = 8;

            }
            else if ($local[0] == '.' || $local[$localLen-1] == '.')

                $isValid = false;
                $problem = 9;

            }
            else if (preg_match('/\\.\\./', $local)) {

                $isValid = false;
                $problem = 10;

            }
        }
    }
    else {

        $problem = 11;

}
    if ($isValid == true) {

        $message = "Message : <br/>" .$text . "<br/><br/>" . "From: " . $name . "<br/>" . $contact;
        $headers = 'From: '. $contact . "\r\n" . 'Reply-To: ' . $contact . "\r\n" . "Content-type: text/html\r\n";
        $mailto = 'net@weedy101.netii.net';
        mail($mailto, $subject, $message, $headers );

    }

header('location: index.php?pass='.$problem);
?>

Fell free to adapt this as I am adapting it from the article "Validate an E-Mail Address with PHP, the Right Way" on http://www.linuxjournal.com/article/9585?page=0,0

<EDIT>

After running through all the help offered here and working through many experiments that is lead to I am still stuck. Although I can get things to work by copying verbatim the original reference articles example at http://www.linuxjournal.com/article/9585?page=0,0 and this is all good, what I can't do is adapt it other than changing the preg match strings which would defeat the object anyway. So if anybody can see a way to make this more adaptable, ie portable as an external function or class so it can be reused at will. I would seriously appreciate the help.

So I'm going to mark this as answered but will keep reading the comments and any new answers in the hope of one day being able to understand what exactly is stopping this subroutine from being separated out and used more flexibly.

Weedy101
  • 13
  • 1
  • 8

3 Answers3

0

There's a sample code directly in the documentation:

if (get_magic_quotes_gpc()) {
    $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
    while (list($key, $val) = each($process)) {
        foreach ($val as $k => $v) {
            unset($process[$key][$k]);
            if (is_array($v)) {
                $process[$key][stripslashes($k)] = $v;
                $process[] = &$process[$key][stripslashes($k)];
            } else {
                $process[$key][stripslashes($k)] = stripslashes($v);
            }
        }
    }
    unset($process);
}
Denis
  • 5,061
  • 1
  • 20
  • 22
  • Thanks for your answer I had missed that in the php manual. Unfortunately it is not working for this situation though and the mail still gets through with the local part quoted out. I also tried to generate a local 'php.ini' file setting the magic quotes to off but still get the same result. – Weedy101 Oct 05 '13 at 21:23
  • I don't think your problem has anything to do with magic quotes, though. – Denis Oct 05 '13 at 21:37
  • Any pointers would be appreciated, I am a novice and learning as I go. If there is something in my script that I have missed, of I have got things in the wrong order, if statements overlapping that shouldn't ect, please let me know. – Weedy101 Oct 05 '13 at 21:59
  • Reading through the [link](http://www.php.net/manual/en/sybase.configuration.php#ini.magic-quotes-sybase) article it suggest's that the problem can also be due to the magic-quotes-sysbase setting which is getting a little to confusing for me to follow accurately. However it also mentions the use of 'addslashes()' and 'stripslashes()' functions so I am about to have a read up on them. – Weedy101 Oct 05 '13 at 22:12
  • Nope, the stripslashes will not take away the " marks being used to escape the bad characters. I think I will need a programatic work around to insert into my form so that the email entered is not detected by the magic-quotes and passed to the validation file. Any ideas on how I might be able to do that? – Weedy101 Oct 05 '13 at 22:39
  • It turns out you are right and it is not the magic quotes settings that has been getting in the way. For an unknown reason the actual email as a string was not being parsed. I am still studying this to find out why. – Weedy101 Oct 08 '13 at 14:45
0

You do know the filter_var function?

var_dump(filter_var('bob@example.com', FILTER_VALIDATE_EMAIL));

It's not perfect but does a way better job than you do...

PS: To validate an email first filter_var it and then use this method here (not my site but first that came up in google for php validate mx) with checkdnsrr if you want to make sure the domain can actually handle email. If no MX records are found, it's safe to assume email won't reach it. Or try a brute force port 25 socket connect too just to be really sure.

CodeAngry
  • 12,760
  • 3
  • 50
  • 57
  • The filter_var is flawed and blocks many legit email addresses as well as allows incomplete addresses. Plus it allows no room for telling users exactly why there email address didn't validate. Often a simple typo is the cause. – Weedy101 Oct 05 '13 at 21:56
  • @Weedy101 If they can't type their email right, they can't type their credit card right neither ;) `filter_var` is good enough for me in real life usage. `(btw: preg_match(\.\.) why not strops(..), to stay efficient.)` – CodeAngry Oct 05 '13 at 22:29
  • As a mere novice I have to work from other peoples examples and had not thought of adapting the check for a .. to a string position argument. I have now experimented heavily with this and the only way I can get that to work is to set another variable to the string position of .. and then use an 'if is boolean variable && ! variable expression which is even longer. If there is another way to get that of anything else shortened for code efficiency please let me know. – Weedy101 Oct 08 '13 at 14:50
0

As per the new edit of my question.

Thanks all who have offered your help it is much appreciated, unfortunately I have failed to make this subroutine portable and flexible. The only way I have been able to implement it at all is verbatim as per the original article on linuxjounal.com http://www.linuxjournal.com/article/9585?page=0,0

There is a working example of this validation subroutine on my temporary home page http://weedy101.netii.net/ by all means have a play with this, and leave me a line or two of guidance too if you can.

For anybody interested I changed the placeholder text color by calling the ::-webkit-input-placeholder (plus the -moz- and -ms- equivalents) for the textarea from within a php tag inside the head element of the index page thus -

<head>

<?php
    if ($problem <> 1)
    {?><style type="text/css">
    <!--
    textarea::-webkit-input-placeholder { background: #ffffff; color: #ff0000!important; }
    textarea:-moz-placeholder { background: #ffffff; color: #ff0000!important; }
    textarea::-moz-placeholder { background: #ffffff; color: #ff0000!important; }
    textarea:-ms-input-placeholder { background: #ffffff; color: #ff0000!important; }
    -->
    </style><?php } ?>
Weedy101
  • 13
  • 1
  • 8