Entwickeln eines sicheren Front-End-Post-Bearbeitungsformulars

Ich möchte eine Front-End-Post-Bearbeitungsfunktion zu einer meiner WordPress-Seiten hinzufügen. Ich habe ein paar Plugins gefunden, die das tun, aber sie passen nicht alle meine Bedürfnisse, also habe ich beschlossen, eine bestehende Lösung anzupassen, um ein eigenes Plugin zu entwickeln, das mit einem Shortcode ein Front-End-Bearbeitungsformular zurückgibt. Mein Plugin funktioniert, ich kann Beiträge bearbeiten und speichern, aber ich kann keine Warnung lösen und ich habe (noch) nicht genügend Kenntnisse, um dieses Plugin sicherer zu machen . Irgendwelche Vorschläge?

Die Warnung:

Warnung: Header-Informationen können nicht geändert werden – Header, die bereits gesendet wurden (Ausgabe gestartet unter … / wp-content / plugins / front-post-edit.php: 139) in … / wp-includes / pluggable.php in Zeile 1228

PS Die Zeile 139 ist die letzte Zeile in meinem Plugin (eine Zeile ohne Code).

Mein Plugin-Code:

<?php /* * Plugin Name: Front Post Editor * */ add_shortcode( 'front_post_edit', 'post_shortcode' ); function post_shortcode() { return getForm(); } function getForm() { if ( !is_user_logged_in()) { echo '

You must be logged in!'; } else { if( 'POST' == $_SERVER['REQUEST_METHOD'] && !empty( $_POST['action'] ) && $_POST['action'] == "edit_post" && isset($_POST['postid'])) { $post_to_edit = array(); $post_to_edit = get_post($_POST['postid']); /* these are the fields that we are editing in the form below */ $title = $_POST['item_title']; $description = $_POST['item_description']; $category = $_POST['item_category']; $location = $_POST['item_location']; $location2 = $_POST['item_location2']; /* this code will save the title and description into the post_to_edit array */ $post_to_edit->post_title = $title; $post_to_edit->post_content = $description; /* this code is a must */ $pid = wp_update_post($post_to_edit); /* save taxonomies: post ID, form field name, taxonomy name, if it appends(true) or rewrite(false) */ wp_set_post_terms($pid, array($_POST['item_category']),'category',false); wp_set_post_terms($pid, array($_POST['item_location']),'location',false); /* update custom fields with the new info */ update_post_meta($pid, 'item_location2', $location2); /* redirect user after done editing */ wp_redirect( home_url( '/myposts' ) ); } /* get post to edit */ $post_to_edit = get_post($_POST['postid']); /* get this post's category taxonomy term id */ $term_name = strip_tags( get_the_term_list( $post_to_edit->ID, 'category', '', ', ', '' ) ); $term_obj = get_term_by('name', $term_name, 'category'); $term_id = $term_obj->term_id; /* array for wp_dropdown_category to display with the current post category selected by default */ $args_cat = array( 'selected' => $term_id, 'name' => 'item_category', 'class' => 'postform', 'tab_index' => 10, 'depth' => 2, 'hierarchical' => 1, 'taxonomy' => 'category', 'hide_empty' => false ); /* get this post's location taxonomy term id */ $term_name2 = strip_tags( get_the_term_list( $post_to_edit->ID, 'location', '', ', ', '' ) ); $term_obj2 = get_term_by('name', $term_name2, 'location'); $term_id2 = $term_obj2->term_id; $args_loc = array( 'selected' => $term_id2, 'name' => 'item_location', 'class' => 'postform', 'tab_index' => 10, 'depth' => 2, 'hierarchical' => 1, 'taxonomy' => 'location', 'hide_empty' => false ); ?>


<input type="text" id="item_title" value="post_title; ?>" tabindex="5" name="item_title" />


<input type="text" value="ID,'item_location2', true); ?>" id="item_location2" tabindex="20" name="item_location2" />
<input type="hidden" name="postid" value="ID; ?>" />

In der Fußzeile jedes Eintrags, der von einer Schleife mit dieser Form generiert wurde, wurde eine Schaltfläche Bearbeiten hinzugefügt:

 <form class="edit-post" action="" method="post"> <input type="hidden" name="postid" value="" />   

Solutions Collecting From Web of "Entwickeln eines sicheren Front-End-Post-Bearbeitungsformulars"

Aus dem Code geht hervor, dass Ihre Warnung darauf zurückzuführen ist, dass die Weiterleitung zu spät erfolgt ist. Weiterleitungen sollten als Faustregel erfolgen, nicht später als die init-Aktion. Und nach der Weiterleitung solltest du sterben () (ich glaube nicht, dass der wp_redirect es für dich tut)

Aus Sicherheitsgründen reicht es nicht aus, zu überprüfen, ob der Benutzer eingeloggt ist. Sie müssen überprüfen, ob er die Post bearbeiten kann, etwa if current_user_can('edit_post',$post_id) . Sie müssen dies sowohl auf der UI-Seite als auch auf der Serverseite überprüfen. Nur weil Sie dem Hacker nicht die Fähigkeit zeigen, heißt das nicht, dass er keine spezielle HTTP-Anfrage erstellen wird, um den Post zu ändern, wenn Sie auf der Serverseite keinen Schutz haben.

Nach einigen Lern- und Forschungsarbeiten habe ich den in meiner Frage beschriebenen Ansatz aufgegeben und tatsächlich herausgefunden, wie die Front-End-Bearbeitungsfunktionalität mit der @TheDeadMedic- Lösung hinzugefügt werden kann . Jetzt habe ich nur zwei kleine Fragen :

1) Gibt es eine bessere Möglichkeit, die Post-ID und das Post-Datum zu verwenden / einzustellen? Ich habe für diese zwei versteckten Eingaben verwendet: foo_id und foo_date .

2) Wie sicher ist die Kommunikation zwischen den Formularen?

Dies ist das Formular, das die Post-ID in die “postid” -Variable bringt und an die “post-form” -Seite weiterleitet:

 
< ?php

Dies ist das Front-End-Formular zum Posten von Bearbeitungsposts (der von mir hinzugefügte Code ist mit // MY CODE ):

 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( '

Please login to post links.

', esc_url( wp_login_url( get_permalink() ) ) ); elseif ( $this->isFormSuccess() ) return '

Nice one, post created.

'; 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( // MY CODE 'foo_id' => FILTER_DEFAULT, 'foo_date' => FILTER_DEFAULT, // END MY CODE 'postTitle' => FILTER_DEFAULT, 'postContent' => FILTER_DEFAULT, 'location2' => 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['postContent'] = wp_check_invalid_utf8( $data['postContent'] ); $data['location2'] = sanitize_text_field( $data['location2'] ); $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( // MY CODE 'ID' => $data['foo_id'], 'post_date' => $data['foo_date'], // END MY CODE '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() { // MY CODE if( 'POST' == $_SERVER['REQUEST_METHOD'] && isset( $_POST['postid'] ) ) { $post_to_edit = array(); $post_to_edit = get_post( $_POST['postid'] ); $this->data['foo_id'] = $post_to_edit->ID; $this->data['foo_date'] = $post_to_edit->post_date; $this->data['item_name'] = $post_to_edit->post_title; $this->data['item_description'] = $post_to_edit->post_content; } // END MY CODE ob_start(); ?>
< ?php foreach ( $this->errors as $error ) : ?>

< ?php echo $error ?>

< ?php endforeach ?>
data['postTitle'] ) ) echo esc_attr( $this->data['postTitle'] ); ?>" />
data['location2'] ) ) echo esc_attr( $this->data['location2'] ); ?>" />
// MY CODE data['foo_id'] ) ) echo esc_attr( $this->data['foo_id'] ); ?>" /> data['foo_date'] ) ) echo esc_attr( $this->data['foo_date'] ); ?>" /> // END MY CODE
< ?php wp_nonce_field( self::NONCE_VALUE , self::NONCE_FIELD ) ?>
< ?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;