Sanitize strings to avoid special characters break javascript generated by php - javascript

I have a php 'search' script that looks for the requested data in a MySQL database and prints a table. Each row of this table can be modified or deleted by clicking on an icon. When you click on one of these icons a javascript function that shows a display is called.
This is the piece of code:
while ($row = mysqli_fetch_row($result)) {
// Define $id
$id = $row[7];
// Sanitize output
$user = htmlentities($row[0]);
$name = htmlentities($row[1]);
$surnames = htmlentities($row[2]);
$email = htmlentities($row[3]);
$role = htmlentities($row[4]);
$access = htmlentities($row[5]);
$center = htmlentities($row[6]);
$message .= "<tr>
<td>" . $user . "</td>" .
"<td>" . $name . "</td>" .
"<td>" . $surnames . "</td>" .
"<td>" . $email . "</td>" .
"<td>" . $role . "</td>" .
"<td>" . $access . "</td>" .
"<td>" . $center . "</td>" .
"<td>" .
"<input type='image' src='../resources/edit.png' id='edit_" . $user . "' class='edit' onclick=edit_user(\"$user\",\"$name\",\"$surnames\",'$email','$role','$access',\"$center\",'$id') title='Editar'></button>" .
"</td>" .
"<td>" .
"<input type='image' src='../resources/delete.png' id='delete_" . $user . "' class='delete' onclick=delete_user(\"$user\",'$role') title='Eliminar'></button>" .
"</td>
</tr>";
}
This is just part of the table I generate. After all this, I encode the table with json_encode and echo it. The echo is captured by an ajax function that decodes it (JSON.parse) and puts it into a div.
The table is correctly rendered and everything works fine with normal characters, but I have detected I can have some problems if I have quotes, slashes and another meaningfull characters. The strings are showed correctly in the table, so there is no problem with php, but the generated javascript doesn't work with some strings.
For example, if I introduce:
</b>5'"
or:
<b>5'6"</b><br><div
as users, when I click on edit or delete icon I get some errors in javascript console:
Uncaught SyntaxError: Invalid regular expression: missing /
home.php:1 Uncaught SyntaxError: missing ) after argument list
Uncaught SyntaxError: missing ) after argument list
Uncaught SyntaxError: Unexpected token ILLEGAL
I have tried with several combination of addslash, replace, htmlentites, htmlspecialchars... but I can't get the right one.
What's the right way to work with this in order to avoid any problem?
Thank you.
EDIT:
I have probed this and it seems to work:
In php I use this function:
function javascript_escape($str) {
$new_str = '';
$str_len = strlen($str);
for($i = 0; $i < $str_len; $i++) {
$new_str .= '\\x' . dechex(ord(substr($str, $i, 1)));
}
return $new_str;
}
and then I use something like
$('<textarea />').html(user).text()
in javascript to decode the string.
Is this safe against XSS attacks?

First, create an HTML-safe JSON string of the array and modify your code to use a data attribute like so:
while ($row = mysqli_fetch_row($result)) {
// Define $id
$id = $row[7];
// Sanitize output
$user = htmlentities($row[0]);
$name = htmlentities($row[1]);
$surnames = htmlentities($row[2]);
$email = htmlentities($row[3]);
$role = htmlentities($row[4]);
$access = htmlentities($row[5]);
$center = htmlentities($row[6]);
$json_str_edit = htmlentities(json_encode(array($row[0], $row[1], $row[2], $row[3], $row[4], $row[5], $row[6], $id)));
$json_str_delete = htmlentities(json_encode(array($row[0], $row[4])));
$message .= "<tr>
<td>" . $user . "</td>" .
"<td>" . $name . "</td>" .
"<td>" . $surnames . "</td>" .
"<td>" . $email . "</td>" .
"<td>" . $role . "</td>" .
"<td>" . $access . "</td>" .
"<td>" . $center . "</td>" .
"<td>" .
"<input type=\"image\" src=\"../resources/edit.png\" id=\"edit_$user\" class=\"edit\" data-user=\"$json_str_edit\" title=\"Editar\"></button>" .
"</td>" .
"<td>" .
"<input type=\"image\" src=\"../resources/delete.png\" id=\"delete_$user\" class=\"delete\" data-user=\"$json_str_delete\" title=\"Eliminar\"></button>" .
"</td>
</tr>";
}
Then create an event listener to catch associated click events in JS like this:
function edit_user(user, name, surnames, email, role, access, center, id) {
// `this` will refer to the html element involved in the event
}
function delete_user(user, role) {
// `this` will refer to the html element involved in the event
}
document.addEventListener('click', function(event) {
if(event.target.hasAttribute('data-user')) {
switch(event.target.className) {
case 'edit':
edit_user.apply(event.target, JSON.parse(event.target.dataset.user));
break;
case 'delete':
delete_user.apply(event.target, JSON.parse(event.target.dataset.user));
break;
}
}
}, false);
Alternatively from the addEventListener method, you can simply add this onclick event listener directly to the element like so (I really don't think it matters in this case):
onclick="edit_user.apply(this, JSON.parse(this.dataset.user))"
FYI It's more common practice to use single quotes in scripts to avoid having to escape the double quote characters. Makes things both cleaner and more standardized.

Related

Change style of a single element in a loop

This might confuse but a serious question.
I'm getting table rows from a loop using php and I'm displaying those table inside a table tag using ajax.
Here for the each row there is an id called productTableRow.
So I want to do is, in this table when I click a specific row, I want to change that clicked row's background color.Just only that row and to take the value of the clicked row attribute called product-id and show it in another hidden input
$(document).on('click', function(e){
if($(e.target).is('#productTableRow')){
var productId = $(e.target).attr('productId');
if(productId == productId){
$(e.target).css('background-color','#128C7E');
} else {
$('.trProductTable').css('background-color', 'transparent');
}
}
});
This is my php code which generating the Table rows,
foreach ($products as $product) {
$responseData .= "<tr id='productTableRow' productId='" . $product->id . "'>";
$responseData .= "<td>" . $product->id . "</td>";
$responseData .= "<td>" . $product->product_name . "</td>";
$responseData .= "<td>" . $product->product_barcode . "</td>";
if ($product->group_id == 0) {
$responseData .= "<td>None</td>";
} else {
$responseData .= "<td>" . $product->group_name . "</td>";
}
$responseData .= "<td>" . $product->product_cost . "</td>";
$responseData .= "<td>" . $product->product_selling . "</td>";
if ($product->product_type == 0) {
$responseData .= "<td>Liquid</td>";
} else if ($product->product_type == 1) {
$responseData .= "<td>Weight</td>";
} else if ($product->product_type == 2) {
$responseData .= "<td>Quantity</td>";
}
$responseData .= "<td>" . $product->created_at . "</td>";
Tried this code but doesn't work, really appreciate your help.
After changing the id to a class, I would try this
$('tr.productTableRow').click(function(){
var productId = $(this).attr('productId');
if(productId === productId){ // Always true
$(this).css('background-color','#128C7E');
} else {
// Do something when false ???
}
});
Edit Note: this code must be run after the table is added to the html, if you need to run it before, put the code inside a $(document).ready(function(){/*code */ });
Edit: Answer based on the comments
$(document).on('click', '.productTableRow', function(){
if(oldObject) {
$(oldObject).css('background-color', 'transparent');
}
var productId = $(this).attr('productId');
if(productId === productId){ // Always true
$(this).css('background-color','#128C7E');
}
oldObject = this;
});
First of all, id has to be specific to one element. Jquery is configured as this. Then you can use $(this).parent(‘tr’)
To get the parent row in the click event that can be to the entire class.
I arrived at my own answer,
$(document).on('click', '.groups-product-sidebar', (e)=>{
//Getting the clicked group attributes
var groupId = $(e.target).attr('groupId');
$('.groups-product-sidebar').parent().css('background-color','transparent');
$(e.target).parent().css('background-color','#128C7E');
});

Why doesn't 'onclick' work when html is sent through php?

There is a javascript in my page that loads a PHP script into a div every second. This PHP is supposed to run a SQL query that loads data from a database.
Here is an extract of the PHP
while($row = mysqli_fetch_array($result))
{
$starttime = $row['start_time'];
$module = $row['module'];
$item = $row['item'];
echo "<tr>";
echo "<td>" . $row['start_time'] . "</td>";
echo "<td>" . $row['module'] . "</td>";
echo "<td>" . $row['item'] . "</td>";
echo "<td>" . $row['status'] . "</td>";
echo "<td>" . $row['accepted'] . "</td>";
echo "<td>" . $row['end_time'] . "</td>";
echo "<td><button id='btnaccept' onclick='acceptBtn()'>ACCEPT</button></td>";
echo "</tr>";
}
And here is the Javascript
<script>
var auto_refresh = setInterval(
(function () {
$("#dataDisplay").load("updatedb.php"); //Load the content into the div
}), 1000);
</script>
As you can see, the last table data is a button that runs a Javascript function
<script>
function acceptBtn() {
window.alert("Accepted");
}
</script>
But unfortunately, clicking this button won't run the function. Any help would be appreciated
Try set listener:
echo "<td><button id='btnaccept'>ACCEPT</button></td>";
.
$(document).on('click', '#btnaccept', acceptBtn);
function acceptBtn(event) {
event.preventDefault();
window.alert("Accepted");
}

Iterating over different divs in Javascript and passing arguments to a script

Background
I am using PHP to created a list of voting sections. Each section is the same except for a unique number, which increases by 1 each time the PHP loops.
I use the PHP variable $n as a counter, and place that in the id attributes in several places in each section.
Current PHP/HTML:
echo "<div id='votesection'>";
echo "<h3 id='rating " . $n . "' style='display:block;'>" .
echo "<h3 id='ratingup " . $n . "' style='display:none;'>" . $ratingup . "</h3>\r\n";
echo "<h3 id='ratingdown " . $n . "' style='display:none;'>" . $ratingdown . "</h3>\r\n";
echo "<div class='arrow-down' onclick='downvote($n)'></div>\r\n";
echo "<div class='arrow-up' onclick='upvote($n)'></div>";
echo "</div>";
Goal
When a user clicks on an arrow down or arrow up, certain divs are hidden or displayed. Example, when the up arrow in my second section is clicked, my <h3 id='ratingup2'></h3> would change to visible.
Current JS
function upvote() {
// Script to hide rating, and rating down and display:block ratingup
// Will also need to execture php sql query to increment event rating by one for event by one
}
function downvote(){
// Same script but to show rating down and decrement rating
}
Should I pass every rating id to the script or is there an easier way to do this that I'm missing?
Passing the ID is the easiest way to do it with plain Javascript.
function upvote(n) {
document.getElementById('ratingup ' + n).style.display="block";
document.getElementById('ratingdown ' + n).style.display="none";
}
function downvote(n) {
document.getElementById('ratingup ' + n).style.display="none";
document.getElementById('ratingdown ' + n).style.display="block";
}
A way to do it without passing the ID would be to put classes on the rating DIVs, and pass this instead.
HTML:
echo "<div id='votesection'>";
echo "<h3 id='rating " . $n . "' style='display:block;'>" .
echo "<h3 class='ratingup' style='display:none;'>" . $ratingup . "</h3>\r\n";
echo "<h3 class='ratingdown' style='display:none;'>" . $ratingdown . "</h3>\r\n";
echo "<div class='arrow-down' onclick='downvote(this)'></div>\r\n";
echo "<div class='arrow-up' onclick='upvote(this)'></div>";
JS:
function upvote(self) {
var parent = self.parentNode;
parent.querySelector(".ratingup").style.display = "block";
parent.querySelector(".ratingdown").style.display = "none";
}
function downvote(self) {
var parent = self.parentNode;
parent.querySelector(".ratingup").style.display = "none";
parent.querySelector(".ratingdown").style.display = "block";
}
You can create only one wrapper with the id votesection_id and then do everything else with js/ajax
echo "<div id='votesection_" . $n . "'>";
echo "<h3 id='rating' style='display:block;'>" .
echo "<h3 id='ratingup' style='display:none;'>" . $ratingup . "</h3>\r\n";
echo "<h3 id='ratingdown' style='display:none;'>" . $ratingdown . "</h3>\r\n";
echo "<div class='arrow-down' onclick='downvote($n)'></div>\r\n";
echo "<div class='arrow-up' onclick='upvote($n)'></div>";
echo "</div>";
<script>
function upvote(id){
// 1. Go To the server with ajax do your stuff 2. return the current upvotes 3.replace the upvotes h3 text
}
function downvote(id){
// 1. Go To the server with ajax do your stuff 2. return the current downvotes 3.replace the downvotes h3 text
}
</script>
As #idioteque says in their comment, spaces in element IDs are not allowed. The best way to get this information into the document is probably with data attributes.
Also, multiple elements with the same id are not allowed, what you probably need in this case are classes. (I'm assuming this chunk of HTML will be repeated multiple times per page.)
Borrowing #Barmar's idea of passing this into the event handler, here's how I'd change the server code:
echo "<div class='votesection' data-rating-id=" . $n . ">";
echo "<h3 class='rating' style='display:block;'>" .
echo "<h3 class='ratingup' style='display:none;'>" . $ratingup . "</h3>\r\n";
echo "<h3 class='ratingdown' style='display:none;'>" . $ratingdown . "</h3>\r\n";
echo "<div class='arrow-down' onclick='downvote(this)'></div>\r\n";
echo "<div class='arrow-up' onclick='upvote(this)'></div>";
echo "</div>";
And the JS:
function upvote(self) {
var parent = self.parentNode;
parent.querySelector(".ratingup").style.display = "block";
parent.querySelector(".ratingdown").style.display = "none";
var id = parent.dataset.ratingId;
// do your AJAX or whatever with id
}
function downvote(self) {
var parent = self.parentNode;
parent.querySelector(".ratingup").style.display = "none";
parent.querySelector(".ratingdown").style.display = "block";
var id = parent.dataset.ratingId;
// do your AJAX or whatever with id
}

Calling a POST variable in PHP-function

I have a PHP-file with multiple php functions in it.
I am sending a Javascript Variable with an AJAX-call, POST method to that PHP-file.`
Now the variable IS accessible in my PHP-file but not in that specific function where I want it...
$("#dropdown").change(function () {
var value = $("#dropdown").val();
console.log(value);
$.ajax({
type: "POST",
dataType: 'text',
url: "PhpFunctions.php",
data: {id:$("#dropdown").val()},
success: function (data) {
console.log(data);
$("div.geselecteerdVliegtuig").fadeIn("slow", function () {
console.log("Vliegtuigdetail faded in");
});
/*
$("div.vliegtuigenEnabled2").hide();
console.log("vliegtuigEnabled ID's hidden");
*/
},
error: function (err) {
alert('error: ' + err);
}
}); //END AJAX CALL`
//I CAN ACCESS DATABASE AND ID IS ACCESSIBLE HERE
//Connect to server
$connect = mysql_connect("localhost", "root", "root") or die(mysql_error());
//Connect to database
$select_db = mysql_select_db("Luchthaven") or die("Could not find database");
$id = $_POST['id'];
echo $id; //WORKS
//NEED TO ACCESS IS HERE
function GeselecteerdVliegtuig() {
makeConnection();
//Query the database
$id = $_POST['id'];
//$query = "SELECT * FROM vliegtuig WHERE vliegtuig_ID = 'PEG431';";
//echo "SELECT * FROM vliegtuig WHERE vliegtuig_ID = 'PEG431';<br/>";
$query = "SELECT * FROM vliegtuig WHERE vliegtuig_ID = '" . $id . "';";
echo "SELECT * FROM vliegtuig WHERE vliegtuig_ID = '" . $id . "';<br/>";
$fetch = mysql_query($query) or die("could not fetch data");
while ($row = mysql_fetch_assoc($fetch)) {
echo "<tr id=" . $row['vliegtuig_ID'] . ">";
echo "<td>" . $row['vliegtuig_ID'] . "</td>";
echo "<td>" . $row['maatschappij'] . "</td>";
echo "<td>" . $row['lengte'] . "</td>";
echo "<td>" . $row['breedte'] . "</td>";
echo "<td>" . $row['kilometerstand'] . "</td>";
echo "<td>" . $row['bouwjaar'] . "</td>";
echo "<td>" . $row['bereik'] . "</td>";
echo "<td>" . $row['aantalMotoren'] . "</td>";
echo "</tr>";
} // END WHILE
mysql_close(); //Make sure to close out the database connection
echo "<b>Connection closed<b><br/><br/>";
}
You can pass the $_POST['id'] variable to that function GeselecteerdVliegtuig($id) and call the function with GeselecteerdVliegtuig($_POST['id'])
Get rid of this line:
$id = $_POST['id'];
as you might want to use your functionality even if your value is not located in your $_POST["id"]. Modify your function header from
function GeselecteerdVliegtuig() {
to
function GeselecteerdVliegtuig($id) {
Call your function this way:
if (isset($_POST['id'])) {
GeselecteerdVliegtuig($_POST['id']);
}
and call your function from the page where you posted the value, make sure that the page where you posted exists, works and responds.
Finally, when everything is working change the way you are working with the database, because your current approach has a security leak due to SQL injection possibilities. What if I visit your page and execute the following in the console:
$("#dropdown").val("0'; delete from vliegtuig where '' = '");
and then trigger the post? It will remove every single record from your table unless you are making sure that these attempts fail.

Using jQuery to get the data of a JSON Object

I am new to jQuery and JSON. I have the following PHP code (getData.php) performs query from the database:
<?php
header('Content-Type: application/json');
....
// some code here
....
$my_arr=array();
// fectching data into array
while($info = mysqli_fetch_array($result))
{
// convert to integer value if there is a bug after passing json_encode
$rev=intval($info['bIRevNum']);
$name=$info['bIName'];
echo "<tr>";
echo "<td>" . $info['bName'] . "</td>";
echo "<td>" . $info['bRevNum'] . "</td>";
echo "<td>" . $info['bIName'] . "</td>";
echo "<td>" . $info['bIRevNum'] . "</td>";
$my_arr[]=array('br'=>$name,'rev'=>$rev);
echo "<td>" . $info['pName'] . "</td>";
echo "<td>" . $info['pRevNum'] . "</td>";
echo "</tr>";
}
// json encode
echo json_encode($my_arr);
?>
After use echo 'json_encode' here I can see the JSON object under this format
[{"br":"itemsb1","rev":37},{"br":"itemb2","rev":45}] on my page.
Now I want to access the integer of rev element of the object (37 and 45) for future usage by jQuery in a different PHP file, lets call it index.php and with the below script
<html>
.....
<script>
$(document).ready(function(){
$("button").click(function(){
$.getJSON("getData.php", function(obj) {
$.each(obj, function(key, value){
$("#div1").append("<li>"+value.rev+"</li>");
});
});
});
});
</script>
...
// test here
<!---jquery--->
<div id="div1"><h2>CHANGE >>>> ....!!!!</h2></div>
<button>Calling from different PHP file</button>
</html>
If it is correct, when I click on the button "Calling from different PHP file" it should appears the value of JSON object as 37, 45.
I have tried many ways, but it does not display anything on my page.
Please help me with this!
It appears your problem is that you are echo'ing the html as well as the JSON. try removing the 'echo' from these lines
echo "<tr>";
echo "<td>" . $info['bName'] . "</td>";
echo "<td>" . $info['bRevNum'] . "</td>";
echo "<td>" . $info['bIName'] . "</td>";
echo "<td>" . $info['bIRevNum'] . "</td>";
echo "<td>" . $info['pName'] . "</td>";
echo "<td>" . $info['pRevNum'] . "</td>";
echo "</tr>";
DO NOT delete this line:
$my_arr[]=array('br'=>$name,'rev'=>$rev);
Also make sure your javascript is syntax correct
$("button").click(function(){
$.getJSON("getData.php", function(obj) {
$.each(obj, function(key, value) {
$("#div1").append("<li>"+value.rev+"</li>");
});
});
});
Ensure that the only content coming back from getData.php is JSON-formatted; otherwise, it won't be parsed correctly. If you visit getData.php in your browser directly, you should only see JSON content, and nothing else (including errors, warnings, etc.). Your jQuery looks good; so the issue would have to be whatever content is coming back from the PHP script. I just whipped up a trivial test case using this PHP:
<?php
header('Content-type: application/json');
$my_arr[]=array('br'=>'something','rev'=>'2.0.5');
echo json_encode($my_arr);
?>
Using the exact HTML you provided, that works just as expected.

Categories

Resources