4
\$\begingroup\$

TL;DR

This month I wanted to improve my WordPress knowledge and create a simple form that wasn't bloated with features but was secure. I wanted to make sure this plugin improved my knowledge of:

  • reCaptcha
  • Akismet
  • AJAX
  • RESTful form submission

After spending the beginning part of the month figuring out WP_REST_Request I was able to create a form plugin. The plugin works and emails who the author of the page is but I was wondering if I could make any improvements to my PHP and if any of my code has a vulnerability:

The PHP:

if (!defined('ABSPATH'))
    die('-1');


function contact_js() {
    if (is_page_template('page-contact.php')) {
        wp_enqueue_script( 'contact_js', site_url() . '/js/contact.js', array('jquery'), '1.0.0', true);
        // URL STRING
        $localized = array(
            'url_string' => site_url(),
        );
        wp_localize_script('contact_js', 'url_object', $localized);
    }
}
add_action('wp_enqueue_scripts', 'contact_js');


function reCaptcha_in_head() {
    if (is_page_template('page-contact.php')) {
        ?><script src='https://www.google.com/recaptcha/api.js'></script><?php
    }
}
add_action('wp_head', 'reCaptcha_in_head');


add_action('rest_api_init', function() {
    register_rest_route('darthvader/v2', '/contact/', array(
        'methods'   => 'POST',
        'callback'  => 'darth_contact_form',
    ));
});


function darth_contact_form(\WP_REST_Request $request) {
    $pre_checks = true;
    if (check_ip_address() == "undefined") :
        $pre_checks = false;
    else :
        $form_ip_address = check_ip_address();
    endif;
    if (check_referrer() == "undefined") :
        $pre_checks = false;
    else :
        $form_referrer = check_referrer();
    endif;
    if (check_user_agent() == "undefined") :
        $pre_checks = false;
    else :
        $form_agent = check_user_agent();
    endif;
    if (akismet_verify_key(akismet_get_key()) != 'valid') :
        $pre_checks = false;
    endif;

    if ($pre_checks !== true ) {
        return new WP_Error('error', 'prechecks failed', array('status' => 400));
    }

    $form_email     = clean_string($request['form_email']);
    $form_name      = clean_string($request['form_name']);
    $form_message   = clean_string($request['form_message']);

    $recaptcha = reCaptcha_check($form_ip_address);
    if ($recaptcha !== true) {
        // return('Recaptcha shows this to be: ' . $recaptcha);
        return new WP_Error('error', 'reCaptcha says spam', array('status' => 400));
    }

    $akismet_outcome = akismet_spam_check($form_ip_address, $form_agent, $form_referrer, $form_email, $form_name, $form_message);
    // return('Is it spam? Akismet says: ' . $akismet_outcome);
    if ($akismet_outcome !== "false") {
        return new WP_Error('error', 'reCaptcha says spam', array('status' => 400));
    }

    $form_success = email_the_message($form_ip_address, $form_agent, $form_referrer, $form_email, $form_name, $form_message);
    if (false === $form_success) {
        return new WP_Error('error', 'email failed to send', array('status' => 400));
    }
    return;
}


// CHECK AKISMET IF IT'S SPAM
function akismet_spam_check($form_ip_address, $form_agent, $form_referrer, $form_email, $form_name, $form_message) {
    if (function_exists('akismet_http_post')) :
            global $akismet_api_host, $akismet_api_port;

            // CALL TO COMMENT CHECK
            $contact_data = array(
                'blog'                  => site_url(),
                'user_ip'               => $form_ip_address,
                'user_agent'            => $form_agent,
                'referrer'              => $form_referrer,
                'comment_type'          => 'contact-form',
                'comment_author'        => $form_name,
                'comment_author_email'  => $form_email,
                'comment_content'       => $form_message,
                'permalink'             => the_permalink(),
                'is_test'               => TRUE, // for testing purposes
            );

            // CONSTRUCT THE QUERY STRING
            $query_string = http_build_query($contact_data);

            // POST IT TO AKISMET
            $response = akismet_http_post($query_string, $akismet_api_host, '/1.1/comment-check', $akismet_api_port);

            // CHECK THE RESULTS
            $result = (is_array($response) && isset($response[1])) ? $response[1] : 'false';

            return $result;
    else :
        return new WP_Error('error', 'Akismet HTTP not found', array('status' => 404));
    endif;
}


// CHECK WITH RECAPTCHA
function reCaptcha_check($form_ip_address) {
    try {
        $url    = 'https://www.google.com/recaptcha/api/siteverify';
        $data   = [
            'secret'   => CAPTACHA_SECRET_KEY, // declared constant in wp-config
            'response' => $_POST['g-recaptcha-response'],
            'remoteip' => $form_ip_address,
        ];
        $options = [
            'http' => [
                'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
                'method'  => 'POST',
                'content' => http_build_query($data)
            ]
        ];
        $context    = stream_context_create($options);
        $result     = file_get_contents($url, false, $context);
        return json_decode($result)->success;
        }
    catch (Exception $e) {
        return null;
    }
}


// TIME
function form_time() {
    $time = clean_string(date("F jS Y, h:ia", time()));
    return $time;
}


// REFERRER
function check_referrer() {
    if (isset($_SERVER['HTTP_REFERER'])) :
        $referer = clean_string($_SERVER['HTTP_REFERER']);
    else :
        $referer = "undefined";
    endif;
    return $referer;
}


// USER AGENT
function check_user_agent() {
    if (isset($_SERVER['HTTP_USER_AGENT'])) {
        $agent = clean_string($_SERVER['HTTP_USER_AGENT']);
    } else {
        $agent = "undefined";
    }
    return $agent;
}


// IP ADDRESS
function check_ip_address() {
    if (isset($_SERVER['REMOTE_ADDR'])) :
        $ip_address = clean_string($_SERVER['REMOTE_ADDR']);
    else :
        $ip_address = "undefined";
    endif;
    return $ip_address;
}


// SANITIZE
function clean_string($string) {
    $string = rtrim($string);
    $string = ltrim($string);
    $string = htmlentities($string, ENT_QUOTES); 
    $string = str_replace("n", "<br>", $string);
    if (get_magic_quotes_gpc()) {
        $string = stripslashes($string);
    }
    return $string;
}


function email_the_message($form_ip_address, $form_agent, $form_referrer, $form_email, $form_name, $form_message) {
     global $post;
    $to         = get_the_author_meta('user_email');
    $subject    = the_title();
    $body = 
        "TIME: "        . form_time()       . "\n" .
        "IP ADDRESS: "  . $form_ip_address  . "\n" . 
        "USER AGENT: "  . $form_agent       . "\n" .
        "EMAIL: "       . $form_email       . "\n" .
        "NAME: "        . $form_name        . "\n" .
        "MESSAGE: "     . $form_message     . "\n";
    // send the awesomeness
    wp_mail($to, $subject, $body);
}

After any improvements are suggested I will break up the PHP into a plugin and utilize WP Settings and Options API.

I did have help with this when I hit roadblocks. If you'd like to see where my faults lied here is a resource list of the Q&As I made to get me to this point:

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.