Разработка безопасной формы отправки на передний конец

Я хочу добавить функциональность отправки на передний план на один из моих сайтов WordPress. Для большего контроля и для лучшего понимания того, как это работает (я не профессиональный программист), я решил использовать в качестве основы для будущей разработки решение с сайта wpkb.com (см. Следующий код). Это решение работает, но вопрос в том, как он защищен от проблем безопасности / вредоносных атак ?

Во-вторых, когда новое сообщение отправляется, оно сохраняется, но также выдает уведомление, и я не понимаю, почему:

Примечание. Неопределенная переменная: hasError in … / submit-from-front.php в строке 106

Это линия 106:

//Check if any error was detected in validation. if($hasError == true) { 

Полный код:

 class WPSubmitFromFront { protected $pluginPath; protected $pluginUrl; public function __construct() { // Set Plugin Path $this->pluginPath = dirname(__FILE__); // Set Plugin URL $this->pluginUrl = WP_PLUGIN_URL . '/submitfromfront'; //Add CSS for the form. add_action('wp_enqueue_scripts', array($this, 'addStyles')); //Add the short code add_shortcode('post_from_front', array($this, 'handleFrontEndForm')); } function handleFrontEndForm() { //Check if the user has permission to publish the post. if ( !current_user_can('publish_posts') ) { echo "<h2>Please Login to post links.</h2>"; return; } if($this->isFormSubmitted() && $this->isNonceSet()) { if($this->isFormValid()) { $this->createPost(); } else { $this->displayForm(); } } else { $this->displayForm(); } } //This function displays the HTML form. public function displayForm() { ?> <div id ="frontpostform"> <form action="" id="formpost" method="POST" enctype="multipart/form-data"> <fieldset> <label for="postTitle">Post Title</label> <input type="text" name="postTitle" id="postTitle" /> </fieldset> <fieldset> <label for="postContent">Content</label> <textarea name="postContent" id="postContent" rows="10" cols="35" ></textarea> </fieldset> <fieldset> <button type="submit" name="submitForm" >Create Post</button> </fieldset> <?php wp_nonce_field( 'front_end_new_post' , 'nonce_field_for_front_end_new_post'); ?> </form> </div> <?php } function addStyles() { // Register the style for the form wp_register_style( 'submitform-style', plugins_url( 'submitfromfront/submitfromfront.css')); wp_enqueue_style( 'submitform-style' ); } function isFormSubmitted() { if( isset( $_POST['submitForm'] ) ) return true; else return false; } function isNonceSet() { if( isset( $_POST['nonce_field_for_front_end_new_post'] ) && wp_verify_nonce( $_POST['nonce_field_for_front_end_new_post'], 'front_end_new_post' ) ) return true; else return false; } function isFormValid() { //Check all mandatory fields are present. if ( trim( $_POST['postTitle'] ) === '' ) { $error = 'Please enter a title.'; $hasError = true; } else if ( trim( $_POST['postContent'] ) === '' ) { $error = 'Please enter the content.'; $hasError = true; } //Check if any error was detected in validation. if($hasError == true) { echo $error; return false; } return true; } function createPost() { //Get the ID of currently logged in user to set as post author $current_user = wp_get_current_user(); $currentuserid = $current_user->ID; //Get the details from the form which was posted $postTitle = $_POST['postTitle']; $contentOfPost = $_POST['postContent'] ; $postSatus = 'publish'; // 'pending' - in case you want to manually aprove all posts; //Create the post in WordPress $post_id = wp_insert_post( array( 'post_title' => $postTitle, 'post_content' => $contentOfPost, 'post_status' => $postSatus , 'post_author' => $currentuserid )); } } $wpSubmitFromFEObj = new WPSubmitFromFront(); 

Solutions Collecting From Web of "Разработка безопасной формы отправки на передний конец"

Надеюсь, кода будет достаточно для описания ключевых моментов, но, пожалуйста, сделайте комментарий, если у вас возникнут дополнительные вопросы:

 <?php class WPSE_Submit_From_Front { const NONCE_VALUE = 'front_end_new_post'; const NONCE_FIELD = 'fenp_nonce'; protected $pluginPath; protected $pluginUrl; protected $errors = array(); protected $data = array(); function __construct() { $this->pluginPath = plugin_dir_path( __file__ ); $this->pluginUrl = plugins_url( '', __file__ ); add_action( 'wp_enqueue_scripts', array( $this, 'addStyles' ) ); add_shortcode( 'post_from_front', array( $this, 'shortcode' ) ); // Listen for the form submit & process before headers output add_action( 'template_redirect', array( $this, 'handleForm' ) ); } function addStyles() { wp_enqueue_style( 'submitform-style', "$this->pluginUrl/submitfromfront.css" ); } /** * Shortcodes should return data, NOT echo it. * * @return string */ function shortcode() { if ( ! current_user_can( 'publish_posts' ) ) return sprintf( '<p>Please <a href="%s">login</a> to post links.</p>', esc_url( wp_login_url( get_permalink() ) ) ); elseif ( $this->isFormSuccess() ) return '<p class="success">Nice one, post created.</p>'; else return $this->getForm(); } /** * Process the form and redirect if sucessful. */ function handleForm() { if ( ! $this->isFormSubmitted() ) return false; // http://php.net/manual/en/function.filter-input-array.php $data = filter_input_array( INPUT_POST, array( 'postTitle' => FILTER_DEFAULT, 'location2' => FILTER_DEFAULT, 'postContent' => FILTER_DEFAULT, )); $data = wp_unslash( $data ); $data = array_map( 'trim', $data ); // You might also want to more aggressively sanitize these fields // By default WordPress will handle it pretty well, based on the current user's "unfiltered_html" capability $data['postTitle'] = sanitize_text_field( $data['postTitle'] ); $data['location2'] = sanitize_text_field( $data['location2'] ); $data['postContent'] = wp_check_invalid_utf8( $data['postContent'] ); $this->data = $data; if ( ! $this->isNonceValid() ) $this->errors[] = 'Security check failed, please try again.'; if ( ! $data['postTitle'] ) $this->errors[] = 'Please enter a title.'; if ( ! $data['postContent'] ) $this->errors[] = 'Please enter the content.'; if ( ! $this->errors ) { $post_id = wp_insert_post( array( 'post_title' => $data['postTitle'], 'post_content' => $data['postContent'], 'post_status' => 'publish', )); if ( $post_id ) { add_post_meta( $post_id, 'location2', $data['location2'] ); // Redirect to avoid duplicate form submissions wp_redirect( add_query_arg( 'success', 'true' ) ); exit; } else { $this->errors[] = 'Whoops, please try again.'; } } } /** * Use output buffering to *return* the form HTML, not echo it. * * @return string */ function getForm() { ob_start(); ?> <div id ="frontpostform"> <?php foreach ( $this->errors as $error ) : ?> <p class="error"><?php echo $error ?></p> <?php endforeach ?> <form id="formpost" method="post"> <fieldset> <label for="postTitle">Post Title</label> <input type="text" name="postTitle" id="postTitle" value="<?php // "Sticky" field, will keep value from last POST if there were errors if ( isset( $this->data['postTitle'] ) ) echo esc_attr( $this->data['postTitle'] ); ?>" /> </fieldset> <fieldset> <label for="postContent">Content</label> <textarea name="postContent" id="postContent" rows="10" cols="35" ><?php if ( isset( $this->data['postContent'] ) ) echo esc_textarea( $this->data['postContent'] ); ?></textarea> </fieldset> <fieldset> <button type="submit" name="submitForm" >Create Post</button> </fieldset> <?php wp_nonce_field( self::NONCE_VALUE , self::NONCE_FIELD ) ?> </form> </div> <?php return ob_get_clean(); } /** * Has the form been submitted? * * @return bool */ function isFormSubmitted() { return isset( $_POST['submitForm'] ); } /** * Has the form been successfully processed? * * @return bool */ function isFormSuccess() { return filter_input( INPUT_GET, 'success' ) === 'true'; } /** * Is the nonce field valid? * * @return bool */ function isNonceValid() { return isset( $_POST[ self::NONCE_FIELD ] ) && wp_verify_nonce( $_POST[ self::NONCE_FIELD ], self::NONCE_VALUE ); } } new WPSE_Submit_From_Front;