SitePoint Sponsor

User Tag List

Results 1 to 10 of 10
  1. #1
    SitePoint Zealot
    Join Date
    Nov 2007
    Location
    Georgia , USA
    Posts
    51
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Help with Boutell's php contact form - "Spot the error"

    I've downloaded and installed a php contact form from Boutell.com. It has one problem, which can be seen immediately here.

    I have no idea what to do about it. I've stared at it long enough, and am only getting more frustrated. I just don't understand PHP well enough to solve this on my own. I don't understand why this...
    PHP Code:
    if (count($messages) > 0) {

            
    $message implode("<br>\n"$messages);

            echo(
    "<h3>$message</h3>\n"); 
    is being executed, since when the page loads there has been no user input, and therefore no error messages should be counted.

    If someone wanted to try to point me in the right direction, without totally giving away the answer, I'd love that. I might learn that way.

    Code for the contact form follows....
    (note: I'm not using the optional Captcha or Accountable features)

    PHP Code:
    <?php
    # Don't put anything above the previous line, not even blank space

    # Copyright 2007, Thomas Boutell and Boutell.Com, Inc. You
    # MAY use this code in your own projects. You MAY NOT
    # represent this code as your own work. If you wish to share
    # this code with others, please do so by sharing the
    # following URL:
    #
    # http://www.boutell.com/newfaq/creating/email.html

    # OPTIONAL: use Accountable to prefill the user's real name and
    # email address. Requires that you install and configure
    # Accountable first. If your site has no use for accounts elsewhere
    # this isn't worth the trouble.
    #
    # If you ARE using Accountable, uncomment the "require" line below.
    # You will probably have to fix the path to find login.php in the
    # appropriate folder.

    # See: http://www.boutell.com/newfaq/creating/accounts.html

    #require "login.php";

    //require '/home/boutell/html/tools/accountable/login.php';      I commented this out April 20, 09

    # OPTIONAL: use my Captcha system to prevent automated
    # abuse of the contact form. You'll need to install and
    # configure the captcha code first. 
    #
    # If you DO have my captcha installed, uncomment the "require" line
    # below. You will probably have to fix the path to find captcha.php
    # in the appropriate folder.
    #
    # See: http://www.boutell.com/newfaq/creating/captcha.html

    #require "captcha.php";
    // require '/home/boutell/html/tools/captcha/captcha.php';       I commented this out April 20, 09

    # The person who receives the email messages
    #$recipient = 'example@example.com';
    $recipient 'XXXXXXXXXXXXX.com';

    # Usually $_SERVER['SERVER_NAME'] is fine, but if you have an unusual
    # hosting setup, you might need to set this manually to 'www.mysite.com'
    #$serverName = $_SERVER['SERVER_NAME'];

    //$serverName = 'www.XXXXXXXX.com';          one option. Doesn't work on wampserver
    $serverName $_SERVER['SERVER_NAME'];

    if (
    $_POST['send']) {
        
    sendMail();
    } elseif ((
    $_POST['cancel']) || ($_POST['continue'])) {
        
    redirect();
    } else {
        
    displayForm(false);
    }

    function 
    displayForm($messages)
    {
        
    # Import $login object from accountable. If we're not using
        # accountable this is null, which is not a problem
        
    global $login;

        
    # Re-display existing input so that the user doesn't have to enter
        # things again when correcting a problem with just one field.
        # Make sure ", <, >, etc. entered by the user are not treated 
        # as part of the HTML of the page

        # If the email address and real name haven't been entered yet,
        # check $_SESSION for them. If Accountable is in use, we can
        # pre-fill these fields for the user.
        
    $escapedEmail htmlspecialchars($_POST['email']);
        
    $escapedRealName htmlspecialchars($_POST['realname']);
        
    $escapedSubject htmlspecialchars($_POST['subject']);
        
    $escapedBody htmlspecialchars($_POST['body']);
        
    $returnUrl $_POST['returnurl'];
        if (!
    strlen($returnUrl)) {
            
    # We'll return the user to the page they came from
            
    $returnUrl $_SERVER['HTTP_REFERER'];
            if (!
    strlen($returnUrl)) {
                
    # Stubborn browser won't give us a referring
                # URL, so return to the home page of our site instead
                
    $returnUrl '/';
            }
        }
        
    $escapedReturnUrl htmlspecialchars($returnUrl);
        
    # Shift back into HTML mode to send the form
    ?>
    <html>
    <head>
    <?php
        
    # Bring in Accountable style sheet if we are using Accountable.
        # Your accountable chrome folder could be somewhere else,
        # so fix the href if you need to
        
    if ($login) {
    ?>
    <link href="/accountable/chrome/login.css" rel="stylesheet" type="text/css">
    <?php
        
    }
    ?>
    <title>Contact XXXXXXXXXX</title>
    </head>
    <body>
    <?php
        
    # Display Accountable login prompt if we are
        # using Accountable
        
    if ($login) {
            
    $login->prompt();
            
    # Fetch email address and real name from Accountable.
            # We don't do this sooner because we want it to work
            # even if the user just finished logging in
            # (and $login->prompt() handles that situation)
            
    if (!strlen($escapedEmail)) {
                
    $escapedEmail htmlspecialchars($_SESSION['email']);
            }
            if (!
    strlen($escapedRealName)) {
                
    $escapedRealName htmlspecialchars($_SESSION['realname']);
            }
        }
    ?>
    <h1>Contact Latitude 17 South</h1>
    <?php
        
    # Shift back into PHP mode for a moment to display
        # the error message, if there was one
        
    if (count($messages) > 0) {
            
    $message implode("<br>\n"$messages);
            echo(
    "<h3>$message</h3>\n");
        }
    ?>
    <form method="POST" action="<?php echo $_SERVER['DOCUMENT_URL']?>">
    <p>
    <input 
        name="email" 
        size="64" 
        maxlength="64" 
        value="<?php echo $escapedEmail?>"/>
        Your Email Address
    </p>
    <p>
    <input 
        name="realname" 
        size="64" 
        maxlength="64" 
        value="<?php echo $escapedRealName?>"/>
        Your Real Name (<i>so our reply won't get stuck in your spam folder</i>)
    </p>
    <p>
    <input 
        name="subject" 
        size="64" 
        maxlength="64"
        value="<?php echo $escapedSubject?>"/> 
        Subject Of Your Message
    </p>
    <p>
    <i>Please enter the text of your message in the field that follows.</i>
    </p>
    <textarea 
        name="body" 
        rows="10" 
        cols="60"><?php echo $escapedBody?></textarea>
    <?php
        
    # Display the captcha if we're using my captcha.php system
        # and the user is not logged in to an Accountable account
        
    if ((!$_SESSION['id']) && (function_exists('captchaImgUrl'))) {
    ?>
    <p>
    <b>Please help us prevent fraud</b> by entering the code displayed in the 
    image in the text field. Alternatively,
    you may click <b>Listen To This</b> to hear the code spoken aloud.
    </p>
    <p>
    <img style="vertical-align: middle" 
        src="<?php echo captchaImgUrl()?>"/> 
        <input name="captcha" size="8"/> 
        <a href="<?php echo captchaWavUrl()?>">Listen To This</a>
    </p>
    <?php
        
    }
    ?>
    <p>
    <input type="submit" name="send" value="Send Your Message"/>
    <input type="submit" name="cancel" value="Cancel - Never Mind"/>
    </p>
    <input 
        type="hidden"
        name="returnurl" 
        value="<?php echo $escapedReturnUrl?>"/>
    </form>
    </body>
    </html>
    <?php
    }

    function 
    redirect()
    {
        global 
    $serverName;
        
    $returnUrl $_POST['returnurl'];
        
    # Don't get tricked into redirecting somewhere
        # unpleasant. You never know. Reject the return URL
        # unless it points to somewhere on our own site.    
        
    $prefix "http://$serverName/";
        if (!
    beginsWith($returnUrl$prefix)) {
            
    $returnUrl "http://$serverName/"
        }
        
    header("Location: $returnUrl");
    }

    function 
    beginsWith($s$prefix)
    {
        return (
    substr($s0strlen($prefix)) === $prefix);
    }

    function 
    sendMail()
    {
        
    # Global variables must be specifically imported in PHP functions
        
    global $recipient;
        
    $messages = array();
        
    $email $_POST['email'];
        
    # Allow only reasonable email addresses. Don't let the
        # user trick us into backscattering spam to many people.
        # Make sure the user remembered the @something.com part
        
    if (!preg_match("/^[\w\+\-\.\~]+\@[\-\w\.\!]+$/"$email)) {
            
    $messages[] = "That is not a valid email address. Perhaps you left out the @something.com part?";
        }
        
    $realName $_POST['realname'];
        if (!
    preg_match("/^[\w\ \+\-\'\"]+$/"$realName)) {
            
    $messages[] = "The real name field must contain only alphabetical characters, numbers, spaces, and the + and - signs. We apologize for any inconvenience.";
        }
        
    $subject $_POST['subject'];
        
    # CAREFUL: don't allow hackers to sneak line breaks and additional
        # headers into the message and trick us into spamming for them!
        
    $subject preg_replace('/\s+/'' '$subject);
        
    # Make sure the subject isn't blank (apart from whitespace)
        
    if (preg_match('/^\s*$/'$subject)) {
            
    $messages[] = "Please specify a brief subject for your message.";
        }
        
        
    $body $_POST['body'];
        
    # Make sure the message has a body
            
    if (preg_match('/^\s*$/'$body)) {
            
    $messages[] = "Your message was blank. Did you mean to say something? Click the Cancel button if you do not wish to send a message.";
        }
        
    # Check the captcha code if the user is NOT logged in to an account
        
    if ((!$_SESSION['id']) && function_exists('captchaImgUrl')) {
            if (
    $_POST['captcha'] != $_SESSION['captchacode']) {
                
    $messages[] = "You did not enter the security code, or what you entered did not match the code. Please try again.";
            }
        }
        if (
    count($messages)) {
            
    # There were errors, so re-display the form with
            # the error messages and let the user correct
            # the problem
            
    displayForm($messages);
            return;
        }
        
    # No errors - send the email    
        
    mail($recipient,
            
    $subject,
            
    $body,
            
    "From: $realName <$email>\r\n" .
            
    "Reply-To: $realName <$email>\r\n");
        
    # Thank the user and invite them to continue, at which point
        # we direct them to the page they came from. Don't allow
        # unreasonable characters in the URL
        
    $escapedReturnUrl htmlspecialchars($_POST['returnurl']);
    ?>
    <html>
    <head>
    <title>Thank You</title>
    </head>
    <body>
    <h1>Thank You</h1>
    <p>
    Thank you for contacting us! Your message has been sent. 
    </p>
    <form method="POST" action="<?php echo $_SERVER['DOCUMENT_URL']?>">
    <input type="submit" name="continue" value="Click Here To Continue"/>
    <input 
        type="hidden"
        name="returnurl" 
        value="<?php echo $escapedReturnUrl?>"/>
    </form>
    </body>
    </html>
    <?php
    }
    ?>
    Last edited by gojira; Apr 28, 2009 at 07:59.

  2. #2
    SitePoint Wizard silver trophybronze trophy Cups's Avatar
    Join Date
    Oct 2006
    Location
    France, deep rural.
    Posts
    6,869
    Mentioned
    17 Post(s)
    Tagged
    1 Thread(s)
    Use var_dump( $messages ) and check what is actually in there.

    user var_dump( count($messages) ) ; so you know what php assesses that to mean.
    PHP Code:
    // put var_dump() s here
    if (count($messages) > 0) { 
    Are you sure you have shown the correct count($messages) - there is another instance further down the page.

  3. #3
    Programming Team silver trophybronze trophy
    Mittineague's Avatar
    Join Date
    Jul 2005
    Location
    West Springfield, Massachusetts
    Posts
    17,269
    Mentioned
    196 Post(s)
    Tagged
    2 Thread(s)
    First, if that email address is real, you should edit out before it becomes SPAM bait.

    The problem line is in the displayForm function. That function is called in 2 places. From the senMail function, which initializes $messages as an array and passes it to the displayForm function and would result in a count 0 if there were no errors.

    But it is also called here
    PHP Code:
    if ($_POST['send']) {
        
    sendMail();
    } elseif ((
    $_POST['cancel']) || ($_POST['continue'])) {
        
    redirect();
    } else {
        
    displayForm(false);

    so in the displayForm function it's
    Code:
        if (count(FALSE) > 0) {
            $message = implode("<br>\n", FALSE);
            echo("<h3>$message</h3>\n");
        }
    According to the documentation http://us2.php.net/count
    If var is not an array or an object with implemented Countable interface, 1 will be returned. There is one exception, if var is NULL, 0 will be returned.
    So 1 is > 0, but as FALSE is not an array implode() fails.

  4. #4
    SitePoint Zealot
    Join Date
    Nov 2007
    Location
    Georgia , USA
    Posts
    51
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I greatly appreciate the help!

    I entered vardump s where recommended, and it produced the following message:
    bool(false) int(1)
    this was above the normal error message...
    Warning: implode() [function.implode]: Invalid arguments passed in /home/XXXXX/public_html/contact.php on line 158


    I'm reading and re-reading the post by Mittineague. Struggling to understand with my limited PHP knowledge. It sounds like I need to set up $messages as an empty array, so that when the displayform function is first called it will have no error messages within it. And apparently the way it is now it has a value of 1. Then, in the displayform function, I should change the "FALSE" back to $messages.

    I hope I'm on the right track....

  5. #5
    SitePoint Zealot
    Join Date
    Nov 2007
    Location
    Georgia , USA
    Posts
    51
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I guess I should have read Mittineague's post just ONE more time. He made it pretty clear where the problem was, and now that the light-bulb has turned on, I've made the change and the form displays without the error message.

    I love PHP, but its a huge struggle to understand, and I'm not having much luck teaching myself. I need more structured education on this. If you can point me to a solid online course for learning PHP, I'd really appreciate it.

    Thanks very much to you both!

  6. #6
    SitePoint Addict
    Join Date
    Apr 2009
    Posts
    248
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Gojira: is this your first language? If so, it's probably not PHP you're finding tough, but programming in general. Good news, though; you'll find that the more you practice, the easier it gets.

    As a good tutorial, I like Practical PHP Programming, an online textbook with examples available at http://www.tuxradar.com/practicalphp for free. I found that the language is fresh enough that I don't get bored, but technical enough that I find it useful. Hang in there, you'll definitely find that one day, you'll wonder how you ever struggled with this.

  7. #7
    SitePoint Zealot
    Join Date
    Nov 2007
    Location
    Georgia , USA
    Posts
    51
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This is my first programming language. And the TuxRadar site seems like it will be a very big help.

    Thanks!

  8. #8
    Programming Team silver trophybronze trophy
    Mittineague's Avatar
    Join Date
    Jul 2005
    Location
    West Springfield, Massachusetts
    Posts
    17,269
    Mentioned
    196 Post(s)
    Tagged
    2 Thread(s)
    There are several ways to deal with the problem. IMHO, the easiest is to pass NULL instead of FALSE.
    PHP Code:
    if ($_POST['send']) {
        
    sendMail();
    } elseif ((
    $_POST['cancel']) || ($_POST['continue'])) {
        
    redirect();
    } else {
        
    displayForm(null);

    Or you could pass an empty array
    PHP Code:
    if ($_POST['send']) {
        
    sendMail();
    } elseif ((
    $_POST['cancel']) || ($_POST['continue'])) {
        
    redirect();
    } else {
        
    $no_messages = array();
        
    displayForm($no_messages);

    Or you could test for it in the function
    PHP Code:
        if ( is_array($messages) && (count($messages) > 0) ) {
            
    $message implode("<br>\n"$messages);
            echo(
    "<h3>$message</h3>\n");
        } 
    Or you could pass nothing and use a default in the function
    PHP Code:
    } else {
        
    displayForm();
    }
    .....
     function 
    displayForm($messages null)

    How code should be written depends on what you want to do with it and how you want to use it.

    For example, with class methods (kind of like functions) that you want to use many times in different scenarios, it's better to keep the code as flexible as possible. In this script, which only runs once at a time, it's perhaps not as important, so requiring the argument without a default value is OK. Although as that page has a date of 2007-06-26 it seems this bug would have been caught and fixed by now. (I've contacted them re this thread)

    I'm curious, how did you fix it?

  9. #9
    SitePoint Zealot
    Join Date
    Nov 2007
    Location
    Georgia , USA
    Posts
    51
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    PHP Code:
    if ($_POST['send']) {
        
    sendMail();
    } elseif ((
    $_POST['cancel']) || ($_POST['continue'])) {
        
    redirect();
    } else {
        
    displayForm($messages); 
    It worked. I suppose this is telling it to display the form with any error messages, and since the form is being displayed for the first time, there can't be any messages (yet).

    I think I prefer the 2nd option you provided. It makes more sense to me.
    PHP Code:
    $no_messages = array();
        
    displayForm($no_messages); 
    and for that matter, why not...
    PHP Code:
    } else {
           
    $messages = array();
           
    displayForm($messages); 
    It would seem to make sense (to me at least) to initialize $messages as an empty array the first time through, rather than introduce a new variable. I'll give this a try.

  10. #10
    Programming Team silver trophybronze trophy
    Mittineague's Avatar
    Join Date
    Jul 2005
    Location
    West Springfield, Massachusetts
    Posts
    17,269
    Mentioned
    196 Post(s)
    Tagged
    2 Thread(s)
    It "worked"
    PHP Code:
    } else {
        
    displayForm($messages); 
    Because at that point in the code $messages is undefined and therefore is null.
    But you are right to do it differently, which ever way makes more sense to you, since it isn't a good idea to introduce errors (in this case an "undefined" NOTICE) into code even if they do "work".


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •