From d70f10977613f06616c4ee8506308290d2d932f0 Mon Sep 17 00:00:00 2001 From: Thorsten Witteler Date: Mon, 23 Oct 2017 13:39:49 +0200 Subject: [PATCH] validate ajax input --- assets/comments.js | 210 ++++++++++++++++++++++++++++----------------- comments.php | 133 ++++++++++++++++++++++------ 2 files changed, 234 insertions(+), 109 deletions(-) diff --git a/assets/comments.js b/assets/comments.js index ab811ff..0964879 100644 --- a/assets/comments.js +++ b/assets/comments.js @@ -1,82 +1,130 @@ -$(document).ready(function () { - - function PhpComment(element) { - this.element = element; - this.init(); - } - - PhpComment.prototype.init = function () { - this.setupVariables(); - this.setupEvents(); - } - - PhpComment.prototype.setupVariables = function () { - this.commentForm = this.element.find(".comments-form"); - this.titleField = this.element.find("#comment_title"); - this.bodyField = this.element.find("#comment_body"); - } - - PhpComment.prototype.setupEvents = function () { - var phpComment = this, - newMedia; - - $.ajax({ - url: '/media_template.php', - method: 'GET', - dataType: 'html', - success: function (data) { - newMedia = data; - } - }); - - phpComment.commentForm.on("submit", function (e) { - e.preventDefault(); - var parentId = 0, - title = phpComment.titleField.val(), - body = phpComment.bodyField.val(); - - if(phpComment.commentForm.parents(".comment").length > 0){ - parentId = phpComment.commentForm.closest(".comment").attr("data-Id"); - } - - $.ajax({ - url: phpComment.commentForm.attr("action"), - method: 'POST', - dataType: 'json', - data: {title: title, body: body, parentId: parentId}, - success: function (data) { - if(!data.created){ - alert("Couldn't create comment"); - return; - } - - newMedia = newMedia.replace("{{id}}", data.id); - newMedia = newMedia.replace("{{title}}", title); - newMedia = newMedia.replace("{{body}}", body); - newMedia = newMedia.replace("{{nested}}", ''); - phpComment.commentForm.before(newMedia); - phpComment.titleField.val(""); - phpComment.bodyField.val(""); - } - }); - }); - - $(document).on("click", ".comment-add-new", function (e) { - e.preventDefault(); - $(this).find(".comments").before(phpComment.commentForm); - }); - $(document).on("click", ".comment-add-reply", function (e) { - e.preventDefault(); - var media = $(this).closest(".comment"); - media.find(">.comment-body>.comment-text").after(phpComment.commentForm); - }); - } - - $.fn.phpComment = function (options) { - new PhpComment(this); - return this; - } - - $(".comments").phpComment(); - +jQuery(document).ready(function () { + var commentForm = $(document).find('.comments-form'); + var commentSection = $(document).find('.comments').first(); + var commentAlert = commentForm.closest('.alert'); + //var newMedia; + //hide form, show link + commentForm.hide(); + $(document).find('.comment-add-new').show(); + //get template for inserting new comments + /* +$.ajax({ + url: '/media_template.php', + method: 'GET', + dataType: 'html', + success: function (data) { + newMedia = data; + } +}); + */ + $('body').on('click', '.comment-add-new-sadf', function (e) { + e.preventDefault(); + alert('asdf'); + $('span').stop().css('opacity', 1).text('myName = ' + e.name).fadeIn(30).fadeOut(1000); + }); + //show comment form above comments section (new comment thread) + $('body').on('click', '.comment-add-new', function (e) { + e.preventDefault(); + //commentForm.hide(1000); + //commentSection.before(commentForm); + $(this).before(commentForm); + commentForm.show('slow'); + //$(this).slideUp(); + }); + //show comment form below selected comment (reply to existing comment) + $('body').on('click', '.comment-add-reply', function (e) { + e.preventDefault(); + var media = $(this).closest('.comment'); + commentForm.hide(); + media.find('>.comment-body>.comment-text').after(commentForm); + commentForm.show('slow'); + }); + // Attach a submit handler to the form + $(commentForm).on('submit', function (event) { + event.preventDefault(); + // Get some values from elements on the page: + //var term = $(this).find( "input[name='s']" ).val(); + //var data = $(this).serializeArray(); + var data = $(this).serialize(); + console.log("Form Data (submit)", JSON.parse(JSON.stringify(data))); + //var url = $(this).attr( "action" ); + var url = '/nested-comments'; + var parentId = 0; + if ($(this).parents('.comment').length > 0) { + parentId = $(this).closest('.comment').attr('data-Id'); + } + // Send the data using post + + //var posting = $.post(url, { parentId: parentId, data: data }, null, 'json'); + var posting = $.post(url, data + '&parentID=' + parentId, null, 'json'); + //$.post( "test.php", $( "#testform" ).serialize() ); + // Put the results in a div + posting.done(function (response) { + alert('success'); + console.log("Response Data (done)", JSON.parse(JSON.stringify(response))); + //response = JSON.parse(response); + var message = response.status ? response.message : 'Error: ' + response.message; + commentForm.after(commentAlert); + commentAlert.empty().append(message); + if (!response.status) { + return; + } + if (response.status) { + var newMedia = ` +
+
+ + user icon + +
+
+
+

{{comment.title}}

+ +
{{'PLUGIN_COMMENTS.WRITTEN_ON'|t}} {{comment.date|e}} {{'PLUGIN_COMMENTS.BY'|t}} {{comment.author}}
+
+
+ {{comment.text}} +
+ {{nested}} +
+
+`; + newMedia = newMedia.replace('{{comment.id}}', response.id); + newMedia = newMedia.replace('{{comment.level|e}}', response.level); + newMedia = newMedia.replace('{{comment.email|trim|lower|md5}}', response.hash); + newMedia = newMedia.replace('{{parent_id}}', response.data.parent_id); + newMedia = newMedia.replace('{{comment.title}}', response.data.title); + newMedia = newMedia.replace('{{comment.text}}', response.data.text); + newMedia = newMedia.replace('{{comment.author}}', response.data.name); + //newMedia = newMedia.replace('{{comment.date|e}}', response.data.name); + if ($( "div[data-Id='" + response.data.parent_id + "']" ).length > 0) { + $( "div[data-Id='" + response.data.parent_id + "']" ).first().after(newMedia); + } else { + $( "div.comments" ).last().prepend(newMedia); + } + //phpComment.commentForm.before(newMedia); + //phpComment.titleField.val(""); + //phpComment.bodyField.val(""); + } + setTimeout(function () { + commentForm.hide(3000); + }, 5000); + }); + posting.fail(function (status, error, title) { + alert('error'); + console.log("Response Data (fail)", JSON.parse(JSON.stringify(status))); + commentForm.after(commentAlert); + commentAlert.empty().append("

TEST

"); + commentAlert.append("

" + status + "

"); + commentAlert.append("

" + error + "

"); + commentAlert.append("

" + title + "

"); + }); + posting.always(function (test) { + //alert("finished, be it successful or not"); + //test = JSON.parse(test); + //test = test.serialize(); + //alert(test); + }); + }); }); diff --git a/comments.php b/comments.php index a6fc7ec..e0b6352 100644 --- a/comments.php +++ b/comments.php @@ -73,9 +73,15 @@ class CommentsPlugin extends Plugin $disable_on_routes = (array) $this->config->get('plugins.comments.disable_on_routes'); $enable_on_routes = (array) $this->config->get('plugins.comments.enable_on_routes'); + $callback = $this->config->get('plugins.comments.ajax_callback'); $path = $uri->path(); + if ($callback === $path) { + $this->enable = true; + return; + } + if (!in_array($path, $disable_on_routes)) { if (in_array($path, $enable_on_routes)) { $this->enable = true; @@ -163,58 +169,126 @@ class CommentsPlugin extends Plugin */ public function onPageInitialized() { + $is_ajax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'; // initialize with page settings (post-cache) // if (!$this->isAdmin() && isset($this->grav['page']->header()->{'star-ratings'})) { // // if not in admin merge potential page-level configs // $this->config->set('plugins.star-ratings', $this->mergeConfig($page)); // } - $this->callback = 'nested-comments'; // $this->callback = $this->config->get('plugins.star-ratings.callback'); // $this->total_stars = $this->config->get('plugins.star-ratings.total_stars'); // $this->only_full_stars = $this->config->get('plugins.star-ratings.only_full_stars'); - + $callback = $this->config->get('plugins.comments.ajax_callback'); // Process comment if required - if ($this->callback === $this->grav['uri']->path()) { + if ($is_ajax || $callback === $this->grav['uri']->path()) { // try to add the comment $result = $this->addComment(); - echo json_encode(['status' => $result[0], 'message' => $result[1], 'data' => ['score' => $result[2][0], 'count' => $result[2][1]]]); - exit(); + echo json_encode([ + 'status' => $result[0], + 'message' => $result[1], + 'data' => $result[2], +// 'data' => [ +// 'score' => $result[2][0], +// 'count' => $result[2][1] +// ] + ]); + exit(); //prevents the page frontend from beeing displayed. } } public function addComment() { - $nonce = $this->grav['uri']->param('nonce'); - if (!Utils::verifyNonce($nonce, 'comments')) { - return [false, 'Invalid security nonce', [0, 0]]; - } - $language = $this->grav['language']; + if (!$_SERVER["REQUEST_METHOD"] == "POST") { + // Not a POST request, set a 403 (forbidden) response code. + http_response_code(403); + return [false, 'There was a problem with your submission, please try again.', [0, 0]]; + } // get and filter the data - $parent_id = filter_input(INPUT_POST, 'parent_id', FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); - $email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING); - $text = filter_input(INPUT_POST, 'text', FILTER_SANITIZE_STRING); - $title = filter_input(INPUT_POST, 'title', FILTER_SANITIZE_STRING); - $name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING); - //$data = $this->getStars($id); - $data = array( - ['parent_id'] => $parent_id, - ['email'] => $email, - ['text'] => $text, - ['title'] => $title, - ['name'] => $name, - ); + if (!isset($_POST['data']) || !is_array($_POST['data'])) { + // Set a 400 (bad request) response code and exit. + http_response_code(400); + return [false, 'missing data', [0, 0]]; + } + $input = array(); + $input['parent_id'] = filter_input(INPUT_POST, 'parentID', FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); + $input['name'] = isset($_POST['data']['name']) ? filter_var($_POST['data']['name'], FILTER_SANITIZE_STRING) : null; + $input['email'] = isset($_POST['data']['email']) ? filter_var($_POST['data']['email'], FILTER_SANITIZE_EMAIL) : null; + $input['text'] = isset($_POST['data']['text']) ? filter_var($_POST['data']['text'], FILTER_SANITIZE_STRING) : null; + $input['date'] = isset($_POST['data']['date']) ? filter_var($_POST['data']['date'], FILTER_SANITIZE_STRING) : null; + $input['title'] = isset($_POST['data']['title']) ? filter_var($_POST['data']['title'], FILTER_SANITIZE_STRING) : null; + $input['lang'] = isset($_POST['data']['lang']) ? filter_var($_POST['data']['lang'], FILTER_SANITIZE_STRING) : null; + $input['path'] = isset($_POST['data']['path']) ? filter_var($_POST['data']['path'], FILTER_SANITIZE_STRING) : null; + $input['form-name'] = filter_input(INPUT_POST, 'form-name', FILTER_SANITIZE_STRING); + $input['form-nonce'] = filter_input(INPUT_POST, 'form-nonce', FILTER_SANITIZE_STRING); +/* + foreach ($_POST['data'] as $field) { + if (isset($field['name']) && isset($field['value'])) { + switch ($field['name']) { + case 'data[name]': + $input['name'] = filter_var($field['value'], FILTER_SANITIZE_STRING); + break; + case 'data[email]': + $input['email'] = filter_var($field['value'], FILTER_SANITIZE_EMAIL); + break; + case 'data[text]': + $input['text'] = filter_var($field['value'], FILTER_SANITIZE_STRING); + break; + case 'data[date]': + $input['date'] = filter_var($field['value'], FILTER_SANITIZE_STRING); + break; + case 'data[title]': + $input['title'] = filter_var($field['value'], FILTER_SANITIZE_STRING); + break; + case 'data[lang]': + $input['lang'] = filter_var($field['value'], FILTER_SANITIZE_STRING); + break; + case 'data[path]': + $input['path'] = filter_var($field['value'], FILTER_SANITIZE_STRING); + break; + case '__form-name__': + $input['form-name'] = filter_var($field['value'], FILTER_SANITIZE_STRING); + break; + case 'form-nonce': + $input['form-nonce'] = filter_var($field['value'], FILTER_SANITIZE_STRING); //$this->grav['uri']->param('nonce'); + break; + default: + //ignore unexpected fields. + } + } + } +*/ + if (!Utils::verifyNonce($input['form-nonce'], 'comments')) { + http_response_code(403); + return [false, 'Invalid security nonce', [$_POST, $input['form-nonce']]]; + } // ensure both values are sent - if (is_null($title) || is_null($text)) { + if (is_null($input['title']) || is_null($input['text'])) { + // Set a 400 (bad request) response code and exit. + http_response_code(400); return [false, 'missing either text or title', [0, 0]]; //return [false, $language->translate('PLUGIN_COMMENTS.FAIL'), $data]; } + $language = $this->grav['language']; + //$data = $this->getStars($id); + $data = array( + 'parent_id' => $input['parent_id'], + 'email' => $input['email'], + 'text' => $input['text'], + 'title' => $input['title'], + 'name' => $input['name'], + 'id' => 99, + 'level' => 0, + 'hash' => md5(strtolower(trim($input['email']))), + ); // sanity checks for parents - if ($parent_id < 0) { - $parent_id = 0; - } elseif ($parent_id > 999 ) { //TODO: Change to 'exists in list of comment ids - $parent_id = 0; + if ($data['parent_id'] < 0) { + $data['parent_id'] = 0; + } elseif ($data['parent_id'] > 999 ) { //TODO: Change to 'exists in list of comment ids + $data['parent_id'] = 0; } //$this->saveVoteData($id, $rating); + // Set a 500 (internal server error) response code. +// http_response_code(500); //$data = $this->getStars($id); return [true, $language->translate('PLUGIN_COMMENTS.SUCCESS'), $data]; } @@ -485,6 +559,9 @@ class CommentsPlugin extends Plugin * Return the latest commented pages */ private function setCommentLevels($comments) { + if(!is_array($comments)) { + return $comments; + } $levelsflat = array(); foreach($comments as $key => $comment) { $levelsflat[$comment['id']]['parent'] = $comment['parent'];