JENS MALMGREN I create, that is my hobby.

Porting my blog for the second time, feedback

This is post #40 of my series about how I port this blog from Blogengine.NET 2.5 ASPX on a Windows Server 2003 to a Linux Ubuntu server, Apache2, MySQL and PHP. A so called LAMP. The introduction to this project can be found in this blog post /post/Porting-my-blog-for-the-second-time-Project-can-start.

The work on porting this blog started 5 September. That is 111 days ago. During this time I have not been working on music. I would so much like to be done with the posts tab and start to work on the other tabs of the blog but there is one thing I need to address first and that is the feedback. Here is the E-R for the Feedback and Post entities:

Last time I did anything with the Feedback was in post 12. That was when I renamed it from Comment to Feedback because MySQL was stubborn and would not let me call it Comment.

The old blog had some kind of 'trackback' feature. Honestly, I never understood it. Somehow when I navigate my own blog BlogEngine.NET creates useless automatic comments to myself. The good thing about this is that the email address is 'trackback' so the first thing I will do is to delete all these.

update Feedback set IsDeleted = 1 where Email 'trackback';
update Feedback set IsDeleted = 1 where Email LIKE '%houzz.com';
update Feedback set IsDeleted = 1 where Author LIKE '%Mongoose%';
update Feedback set IsDeleted = 1 where IsSpam = 1;

After sifting through the feedback I came up with this set of SQL statements to clean the database. So these people finally have it. They bombarded my blog several years with useless Spam comments and finally they get what they were longing for all the time: to be mentioned in my blog, in a SQL statement deleting their comments, how sad is that?

I will incorporate these clean-up statements in my perl script importing the blog. Then in my next round of importing I will get a fresh nice cleaned set of feedback in my blog.

So now when I cleaned the feedback I can make them appear as well.

# http://www.jens.malmgren.nl/post/Porting-my-blog-for-the-second-time-feedback.aspx
$strFeedbackQuery = "SELECT p.ID, p.Slug, fb.Content, fb.Date FROM Post p, Feedback fb WHERE Slug = ? AND fb.PostID = p.ID AND fb.IsDeleted = 0";
$result = $mysqli-≻query(GetQueryWithData($strFeedbackQuery,$strSlug)) or die("Error query.." . mysqli_error($mysqli));
$strFeedbackTable = "≺div class = 'feedback'≻
";
$iFeedbackCount = 0;
while ($row = mysqli_fetch_array($result))
{
	$fbcontent = $row["Content"];
	$fbcontent.preg_replace("/
/", "≺br≻", $fbcontent);
	$dtFeedbackOn = new DateTime($row["Date"]);
	$strFeedbackTable .= "≺div≻";
	$strFeedbackTable .= "≺time datetime = '" . $dtFeedbackOn-≻format(DateTime::ATOM) . "'≻" . $dtFeedbackOn-≻format(DateTime::RFC850) . "≺/time≻
";
	$strFeedbackTable .= "≺div≻" . $fbcontent . "≺/div≻";
	$strFeedbackTable .= "≺/div≻";
	$iFeedbackCount++;
}
if ($iFeedbackCount == 0)
{
	$strFeedbackTable = "";
}
else
{
	$strFeedbackTable .= "≺/div≻
";
}
$fbFeedBackNum1 = rand(2 , 4);
$fbFeedBackNum2 = rand(3 , 7);

You can see that things starts to come together. The query is secured with GetQueryWithData and the datetime is presented with my time routine. I talk about line 25 and 26 later.

In the CSS I added some simple rules for the presentation of the feedback:

/* http://www.jens.malmgren.nl/post/Porting-my-blog-for-the-second-time-feedback.aspx */
.feedback div
{
	background-color: #EEEEEE;
	color:#646473;
	margin-top:7px;
}

.feedback div div
{
	padding: 5px;
}

.feedback div time
{
	display:block;
	background-color:#777777;
	color:#EEEEEE;
	padding:2px 5px 2px 5px;
}

I showed my new blog layout to DD and she said the layout was "so much 2007". Hmm... Well CSS 2.1 was final on 19 July 2007 so she was spot on! If I go and delete all rounded corners? Then it becomes 2011 according to DD. Well I keep it like this and figure out the layout another time.

When it is possible to present the feedback we also want to be able to submit feedback. To do that I need to create a form as I did before.

≺form id = "fbform" action = "≺?php
# http://www.jens.malmgren.nl/post/Porting-my-blog-for-the-second-time-feedback.aspx
echo "/post/".$strSlug;
?≻" method = "post"≻
	≺textarea id = "fb" name = "fb" placeholder = "Enter your feedback here..."≻≺/textarea≻
	Enter the answer of ≺?php echo($fbFeedBackNum1 . " + " . $fbFeedBackNum2); ?≻ here below to unlock the submit button.
	≺input type = "text" id = "fbtest" name = "fbtest" placeholder = "≺?php echo($fbFeedBackNum1 . " + " . $fbFeedBackNum2); ?≻ = ?"≻
	≺input id = "fbsubmit" type = "submit" value = "Submit" disabled = "disabled"≻
	≺div id = "fberror"≻Cannot accept feedback with any of these characters≺br≻: [ ] { } ≺ ≻ \ / ' " + - * = % @ ; & | $ www .co≺br≻If you need to send me a link or something personal you can do that on jens at malmgren dot nl.≺/div≻
≺/form≻

It is much going on here so I will explain all the rows:

  1. On line 1 the form tag is specified. It has the id 'fbform' and like so we can reference it from javascript etc. The action is set to point to exactly the same page. Later I will explain what happens when the same page is loaded after pressing the submit button.
  2. Simply a comment on line 2.
  3. On line 3 the value of the action attribute is emitted which is the same slug as the current post.
  4. On line 4 we specify that the form will issue a post (to the action url) when the form is submitted. There are other methods as well but I use post here.
  5. Here is the textarea specified. I gave it the id = 'fb' and when still not filled in the hint will be "Enter your feedback here..."
  6. It will be necessary to avoid that robots fill in the form so I decided to have a simple kind of test. The test is two numbers that the user will need to add up. On line 6 I put an explanation for what to enter in the test field. The hint is generated dynamically based on two random numbers that you could see on line 25 and 26 of the previous php excerpt.
  7. On line 7 the answer field of the test is provided. The id is fbtest. Here I let the placeholder be generated dynamically to present the test.
  8. Then we have the submit button to click to submit the feedback. I set its property disabled to disabled so that it appears disabled when the page is displayed.
  9. On line 9 we have a hidden text that can be displayed in case of error.
  10. Here ends the form.

This is all good an well but when there is text being changed then we need to validate things and when we found that all is fine then we need to enable the submit button. How can we do that? I do this with jQuery and JavaScript.

First of all I create a variable that will hold a function.

var $keytest = function()≺br /≻{≺br /≻    ...≺br /≻};

Inside my document ready function I can connect my new function in $keytest in such way that when there is text typed in either the textarea or the fbtest field then my $keytest function will be called. The document ready function is called when the page has finished loading. Here is how I hook up the validation routine to the two fields of the form:

$('#fb,#fbtest').keyup($keytest);

This is to tell jQuery that for #fb and #fbtest whenever there is a keyup event then $keytest will be called.

var $keytest = function()
{
	var strFb = $('#fb').val();
	var strFbTest = $('#fbtest').val();
	var bErr = false;

	var re = /[\\'\"%@:;≺≻*/&$=+[]{}|-]|www|.co/g;
	if (re.test(strFb) || re.test(strFbTest))
	{
		$('#fberror').css( "display", "block" );
		bErr = true;
	}
	else
	{
		$('#fberror').css( "display", "none" );
	};
	
	var reNum = /^[0-9]+$/;
	if (reNum.test(strFbTest))
	{
		var iNum = parseInt(strFbTest);
		bErr = (iNum != ≺?php echo($fbFeedBackNum1 + $fbFeedBackNum2); ?≻);
	}
	else
	{
		bErr = true;
	}

	if (strFb.length == 0 ||  bErr)
	{
		$('#fbsubmit').prop('disabled', true);
	}
	else
	{
		$('#fbsubmit').prop('disabled', false);
	};

};

Here we switch between the layers and programming languages as quick as you can blink. This here is JavaScript with jQuery. I would like to explain what is going on because I think you might appreciate it. No? Yes.

  1. On line 1 we see the $keytest variable being assigned the value of an anonymous function. In some programming languages it is common to have functions that can act as a variable but for some languages it is less common. Get used to it.
  2. Start of block of the anonymous function. It ends on line 38.
  3. Here I declare the variable strFb and I give it the content of the fb text area.
  4. Here I decrare the variable strFbTest and I give it the content of the fbtest input field.
  5. This is a boolean variable that I initialized to false.
  6. Empty line.
  7. Here I declare a variable to hold a regular expression object. The expression finds special characters that I don't want to accept.
  8. Here I test the content of both the fb and fbtest field.
  9. Start of block of what happens if the fields contains an unwanted character. It ends on line 12.
  10. Here I display the error message.
  11. Set the bErr to true so that I later in the routine can enable or disable the submit button based on the state of the input fields.
  12. End of the block.
  13. Here is what will happen if there was no unwanted characters found.
  14. Start of block.
  15. Hiding the error message in case it was visible. No need to set bErr to false because it was initialized to false.
  16. End of block.
  17. Empty line.
  18. Here I declare another variable with a regular expression and this expression will find out if all the content of a field is digits and digits only.
  19. Here I test the fbtest content to see if it is digits only.
  20. Now if the fbtest field was digits only then we start a block to do things here.
  21. Here we convert the text of the number into the integer value. That way we can calculate with it.
  22. Here we assign bErr the result of a comparison. The comparison is between the number as it was entered by the user in fbtest and the sum of fbFeedBackNum1 and fbFeedBackNum2. If iNum is different than the sum of these two then bErr will become true.
  23. End of block.
  24. Else.
  25. Start of block.
  26. This is what takes place if the fbtest field was not found to contain only digits. Then bErr is set to true.
  27. End of block.
  28. Empty line.
  29. Here we test if either fb is an empty field or earlier an error has been detected.
  30. Start of block.
  31. There was something wrong so here we disable the submit button. By doing so it is not possible to submit any incorrect feedback.
  32. End of block.
  33. Else.
  34. Start of block.
  35. Here all is fine. So we enable the submit button.
  36. End of block.
  37. Empty line.
  38. End of function.

Here you see that a function contains a story!

So far when someone pressed the submit button then the same page was reloaded but what happens then? I figured I had to detect a load situation when the page had been called as the result of a submit to a form.

# http://www.jens.malmgren.nl/post/Porting-my-blog-for-the-second-time-feedback.aspx
if (isset($_POST['fb']) && $_POST['fb'] != "")
{
	$fbpost = $_POST['fb'];
	$fbquery =
		'INSERT INTO Feedback	(PostID,	Date,	Author,	Email,	IP,	Content,	IsApproved,	IsDeleted,	IsSpam) ' .
		'VALUES 				(?,			NOW(),	?,		?,		?,	?,			1,			0,			0     )';
	$fqquerywithdata = GetQueryWithData($fbquery, $strID, "a", "e", "i", $fbpost);
	$mysqli-≻query($fqquerywithdata) or die("Error query.." . mysqli_error($mysqli));
	$_POST['fb'] = "";
}

This is straight forward. I placed this routine before the routine gathering available feedback so that the newly inserted feedback would also be visible.

When I came so far I could not get newlines to survive. It was really difficult to find what the problem was. Do you remember when I talked about the SQL injection challenge? So when I made that routine I filtered the newlines. Now I could just change the filtering so that be nothing and becomes
.

Here is one of the best feedbacks I got on my blog from Naarden vesting.

Great! Now I finished the feedback!!!

This is how far I came 2015 with the blog porting project. I started working on the feedback on December 25 and now it is New Years eve. I hope, I really hope that this project will be live in the first part of 2016. I promise nothing though.

HAPPY NEW YEAR!

Regards,
Jens

I was born 1967 in Stockholm, Sweden. I grew up in the small village Vågdalen in north Sweden. 1989 I moved to Umeå to study Computer Science at University of Umeå. 1995 I moved to the Netherlands where I live in Almere not far from Amsterdam.

Here on this site I let you see my creations.

I create, that is my hobby.