I need to escape text that is being outputted via AJAX. If I submit script to the database, like <script>alert('hello world');</script>, then a popup is executed on the page.
This here is my function that is setting the data, and then grabbing data to be sent via AJAX.
function add_order() {
if($_SERVER['REQUEST_METHOD'] == "POST") {
$add_order = $this->order_model->set_order($_POST['text']);
if($add_order==false){
echo "fail";
return false;
}
$order_data = $this->order_model->get_order_by_id($add_order);
echo json_encode($order_data);
return true;
}
}
Jquery Code:
$('#create_order').submit(function(){
$.post('/order/add_order/', $('#create_order').serialize(), function(data){
var obj = $.parseJSON(data);
var obj_item = obj[0];
$('tr.'+obj_item.id).append("<td>" + obj_item.text + "</td>");
msg('success', 'Part #'+obj_item.number+' has been successfully created');
});
}
return false;
});
How do I stop obj_item.text from executing scripts?
You need to build DOM elements and set text instead of building HTML:
$("<td />", { text: obj_item.text }).appendTo('tr.tr.' + obj_item.id);
If the submitted data can only contain plain text, ensure that you use .text() to re-insert it back into the DOM - using .text will prevent any embedded tags from being rendered as HTML or otherwise handled by the browser.
You should also validate data on the server before it's stored, and for extra measure perform client-side verification before posting the data to the server. IMHO, it's better to reject bad data than to simply escape it.
Related
i am try to load B.php from A.php after execution in the function and pass some data using a post array from A.php to B.php within same time.
code list as follows
A.php
<script type="text/javascript">
alert_for_the_fucntion();
window.location.href = "B.php";
function alert_for_the_fucntion() {
$.post("B.php", {action: 'test'});
}
</script>
B.php
<?php
if (array_key_exists("action", $_POST)) {
if ($_POST['action'] == 'test') {
echo 'ok';
}
}
?>
for testing purpose i tried to echo something in the B.php. but currently this is not working. have i done any mistakes? or is there any possible method to do this.
Your code does this:
Tells the browser to navigate to B.php (using a GET request)
Triggers a POST request using XMLHttpRequest
The POST request probably gets canceled because the browser immediately leaves the page (and the XHR request is asynchronous). If it doesn't, then the response is ignored. Either way, it has no effect.
You then see the result of the GET request (which, obviously, doesn't include $_POST['action']) displayed in the browser window.
If you want to programmatically generate a POST request and display the result as a new page then you need to submit a form.
Don't use location. Don't use XMLHttpRequest (or anything that wraps around it, like $.ajax).
var f = document.createElement("form");
f.method = "POST";
f.action = "B.php";
var i = document.createElement("input");
i.type = "hidden";
i.name = "action";
i.value = "test";
f.appendChild(i);
document.body.appendChild(f);
f.submit();
If you want to process the results in JavaScript then:
Don't navigate to a different page (remove the line using `location)
Add a done handler to the Ajax code
e.g.
$.post("B.php", {action: 'test'}).done(process_response);
function process_response(data) {
document.body.appendChild(
document.createTextNode(data)
);
}
Try this:
Javascript:
<script type="text/javascript">
window.onload = alert_for_the_fucntion;
function alert_for_the_fucntion() {
$.post("B.php",
{
action: 'test'
},
function(data, status){
if(status=="success"){
alert(data);
}
}
);
}
</script>
PHP
<?php
if(isset($_POST['action'])){
echo $_POST['action'];
}
?>
I currently have a servlet setup to send over a list of our active servers. The method grabs the servlet data, processes it, then injects the html into the datalist tag. HTML injection process works, but when I'm splitting the array by the concat separator (which I've done before), I get no values. Below I'll explain with code examples:
HTML:
<label for="server_id_text">Server ID: </label>
<input id="server_id_text" list="server_names" name="server_id" required>
<datalist id="server_names">
<!--This gets injected with the active servers grabbed through a get request-->
</datalist>
Javascript connecting to server to get data:
Note: serverList is a global variable.
var serverList = "";
function setupAutoComplete() {
$.get(baseURL + "/SupportPortal", function (data, status) {
console.debug("Status with auto comp id: " + status);
serverList = data;
console.debug("server list auto comp at post mailing: " + serverList);
});
}
This method is called in the function that is called when the onload event is called in the body tag
Here are the two methods that inject the html:
function setupServerName() {
document.getElementById("server_names").innerHTML = getServerListHTML();
}
function getServerListHTML(){
console.debug("Autocomplete process running...");
var servArr = String(serverList).split('*');
var html = '';
var temp = '<option value="{serverName}">';
console.debug("Array:" + servArr.toString());
if (serverList == 'undefined' || servArr.length == 0){
console.debug("serverList is empty...");
return '';
}
for (var i =0; i < servArr.length; ++i){
html += temp.replace("{serverName}", servArr[i]);
}
console.debug("html: " + html);
console.debug("ServList size " + servArr.length);
return html;
}
When the page loads, setupAutoCompelte() is called first. Then, setupServerName() is called.
My issue is that after I load the page, I get the correct response from the server. For instance, I'll get server1*server2 as a response to the jQuery $.get(...) call. Then I go to split the string into an array, and I get back an empty html tag (<option value="">);
Also, the debug console info are as follows:
Autocomplete process running...
Array:
html: <option value="">
ServList size 1
Status with auto comp id: success
server list auto comp at post mailing: server1*server2
Thanks for the help!
I believe that your setupServerName() function is being called before the AJAX request in setupAutoComplete() returns, so your serverList is an empty string at that point. What you need to do is populate your <datalist> from inside your AJAX callback in setupAutoComplete().
// setup autocomplete datalist
function setupAutoComplete() {
var $datalist = $('#server_names');
$.get(baseURL + '/SupportPortal').then(function (data) {
// update datalist
if (!data || !data.length) {
// no servers, empty list
$datalist.html('');
} else {
// create options html:
// reduce array of server names
// to HTML string, and set as
// innerHTML of the dataset
$datalist.html(data.split('*').reduce(function (html, server) {
return html + '<option value="' + server + '">\n';
},''));
}
});
}
// on page load, setup autocomplete
$(function () {
setupAutoComplete();
});
As you can see from "debug console info":
the get function is asyncrhonous so you need to change your setupAutoComplete get part to:
$.get(baseURL + "/SupportPortal", function (data, status) {
console.debug("Status with auto comp id: " + status);
serverList = data;
setupServerName();
console.debug("server list auto comp at post mailing: " + serverList);
});
On page load try to call directly the setupServerName function within the success event of get function. A different approach is to divide the setupServerName function so that the part related to the serverList variable becomes part of another function.
The serverList variable is global but its content is filled after the setupServerName is executed.
I have a PHP script setup that echo's JSON responses depending on what the user has done (or not done as the case may be):
The responses look like this:
{"type":"error","response":"Script error, please reload the page and try again.
Code: [NAct]","title":"Exception","hide":false}
Each response is generated like this:
echo $form -> ajax_response('error', 'Script error, please reload the page and try again.<br>Code: [NAct]', 'Exception', false);
This is picked up by pNotify and displayed - lovely. (See below .done function for ajax request)
request.done(function(msg) {
//validate json response
if (!tryParseJSON(msg)) {
document.write(msg);
} else {
var array = json_to_array(msg);
}
if (array['type'] !== 'none') {
if (array['title'] !== null) {
pushNotification(array['title'], array['response'], array['type'], array['hide']);
} else {
pushNotification(ucfirst(array['type']), array['response'], array['type'], array['hide']);
}
}
ready_status();
});
If the response cannot be validated by tryParseJSON(); the reponse is written directly to the page for debugging.
The problem is when I echo multiple responses back like this:
{"type":"error","response":"Script error, please reload the page and try again.
Code: [NAct]","title":"Exception","hide":false}
{"type":"error","response":"Script error, please reload the page and try again.
Code: [NDat]","title":"Exception","hide":false}
tryParseJSON() sees it as mumbo jumbo and prints it to the page.
Question
How do i pick up the above two lines as separate responses and parse them through my function and sub-sequentially to pNotify without combining them into a single JSON array?
Solution
As pointed out this was over complicated. Instead I combined each response (PHP side) into a an array:
$res['json'][] = $form -> ajax_response('error', 'Script error, please reload the page and try again.<br>Code: [NAct]', 'Exception', false);
Then echo'ed it at the end of the script:
echo json_encode($res['json');
On client side, I used a for loop, sending them to pNotify in each iteration:
request.done(function(msg) {
//validate json response
if (!tryParseJSON(msg)) {
document.write(msg);
} else {
var obj = json_to_array(msg);
}
for (var i=0;i<obj.length;i++) {
if (obj[i]['type'] !== 'none') {
if (obj[i]['title'] !== null) {
pushNotification(obj[i]['title'], obj[i]['response'], obj[i]['type'], obj[i]['hide']);
} else {
pushNotification(ucfirst(obj[i]['type']), obj[i]['response'], obj[i]['type'], obj[i]['hide']);
}
}
}
ready_status();
});
Instead of creating so sperate JSON-Outputs merge it to one single output string.
For this just wrap your two arrays you are currently outputting separately in an array like so
$myOutput[0] = responseArray1;
$myOutput[1] = responseArray2;
echo json_encode($myOutput);
This way you will get a valid JSON-response. Everything else is just some dirty workaround and causes shivers to everyone who has to review your work.
this is the js code
function startChatSession(){
$.ajax({
url: "chat.php?action=startchatsession",
cache: false,
dataType: "json",
success: function(data) {
username = data.username;
$.each(data.items, function(i,item){
if (item) { // fix strange ie bug
chatboxtitle = item.f;
if ($("#chatbox_"+chatboxtitle).length <= 0) {
createChatBox(chatboxtitle,1);
}
if (item.s == 1) {
item.f = username;
}
if (item.s == 2) {
$("#chatbox_"+chatboxtitle+" .chatboxcontent").append('<div class="chatboxmessage"><span class="chatboxinfo">'+item.m+'</span></div>');
} else {
$("#chatbox_"+chatboxtitle+" .chatboxcontent").append('<div class="chatboxmessage"><span class="chatboxmessagefrom">'+item.f+': </span><span class="chatboxmessagecontent">'+item.m+'</span></div>');
}
}
});
here +item.m+ holds a plain text
if it contains html tags then it returns html tags also
for example +item.m+ contains
<b>Hello</b>
i want output to be
Hello
but i am getting same output as
<b>Hello</b>
this code is implemented in a IM chat and i need html code to be executed in the chat window. . .so please help me by suggesting to get html execution here
Thank you
it seems you have <b> instead of a real <br>, to fix it do this:
var itemText = item.m
.replace(/<b>/g, '<b>')
.replace(/<\/b>/g, '</b>');
then use itemText instead of item.m in the code, like this:
var itemText = item.m
.replace(/<b>/g, '<b>')
.replace(/<\/b>/g, '</b>');
if (item.s == 2) {
$("#chatbox_"+chatboxtitle+" .chatboxcontent").append('<div class="chatboxmessage"><span class="chatboxinfo">'+itemText+'</span></div>');
} else {
$("#chatbox_"+chatboxtitle+" .chatboxcontent").append('<div class="chatboxmessage"><span class="chatboxmessagefrom">'+item.f+': </span><span class="chatboxmessagecontent">'+itemText+'</span></div>');
}
and if you want to do it for some other tags like this:
Hello
you can do this like:
var itemText = item.m
.replace(/<\/a>/g, '</a>')
.replace(/<a/g, '<a')
.replace(/>/g, '>');
On the PHP side, don't use htmlentities() to encode the content that you return. When you do, the server returns the HTML code of the character < and >, respectively < and >.
It seems that you are receiving encoded text from your server. Trying applying unescape() on your string before concatenating your strings.
Decode the HTML entities , using .html jQuery function decodes the entities
item.m = $('<div>').html(item.m).text();
but I recommend you to remove the entities on server side, I see you are developing a chat so you better remove any HTML tags for security concerns not sure how are you working with the messages but users sometimes can do cross site scripting.
I have a MVC3 action method with 3 parameters like this:
var url = "/Question/Insert?" + "_strTitle='" + title + "'&_strContent='" + content + "'&_listTags='" + listTags.toString() + "'";
and I want to call this by normal javascript function not AJAX (because it's not necessary to use AJAX function)
I tried to use this function but it didn't work:
window.location.assign(url);
It didn't jump to Insert action of QuestionController.
Is there someone would like to help me? Thanks a lot
This is more detail
I want to insert new Question to database, but I must get data from CKeditor, so I have to use this function below to get and validate data
// insert new question
$("#btnDangCauHoi").click(function () {
//validate input data
//chủ đề câu hỏi
var title = $("#txtTitle").val();
if (title == "") {
alert("bạn chưa nhập chủ đề câu hỏi");
return;
}
//nội dung câu hỏi
var content = GetContents();
content = "xyz";
if (content == "") {
alert("bạn chưa nhập nội dung câu hỏi");
return;
}
//danh sách Tag
var listTags = new Array();
var Tags = $("#list_tag").children();
if (Tags.length == 0) {
alert("bạn chưa chọn tag cho câu hỏi");
return;
}
for (var i = 0; i < Tags.length; i++) {
var id = Tags[i].id;
listTags[i] = id;
//var e = listTags[i];
}
var data = {
"_strTitle": title,
"_strContent": content,
"_listTags": listTags.toString()
};
// $.post(url, data, function (result) {
// alert(result);
// });
var url = "/Question/Insert?" + "_strTitle='" + title + "'&_strContent='" + content + "'&_listTags='" + listTags.toString() + "'";
window.location.assign(url); // I try to use this, and window.location also but they're not working
});
This URL call MVC action "Insert" below by POST method
[HttpPost]
[ValidateInput(false)]
public ActionResult Insert(string _strTitle, string _strContent, string _listTags)
{
try
{
//some code here
}
catch(Exception ex)
{
//if some error come up
ViewBag.Message = ex.Message;
return View("Error");
}
// if insert new question success
return RedirectToAction("Index","Question");
}
If insert action success, it will redirect to index page where listing all question include new question is already inserted. If not, it will show error page. So, that's reason I don't use AJAX
Is there some one help me? Thanks :)
Try:
window.location = yourUrl;
Also, try and use Fiddler or some other similar tool to see whether the redirection takes place.
EDIT:
You action is expecting an HTTP POST method, but using window.location will cause GET method. That is the reason why your action is never called.
[HttpPost]
[ValidateInput(false)]
public ActionResult Insert(string _strTitle, string _strContent, string _listTags)
{
// Your code
}
Either change to HttpGet (which you should not) or use jQuery or other library that support Ajax in order to perform POST. You should not use GET method to update data. It will cause so many security problems for your that you would not know where to start with when tackling the problem.
Considering that you are already using jQuery, you might as well go all the way and use Ajax. Use $.post() method to perform HTTP POST operation.
Inside a callback function of the $.post() you can return false at the end in order to prevent redirection to Error or Index views.
$.post("your_url", function() {
// Do something
return false; // prevents redirection
});
That's about it.
You could try changing
var url = "/Question/Insert?" + "_strTitle='" + title + "'&_strContent='" + content + "'&_listTags='" + listTags.toString() + "'";
to
var url = "/Question/Insert?_strTitle=" + title + "&_strContent=" + content + "&_listTags=" + listTags.toString();
I've removed the single quotes as they're not required.
Without seeing your php code though it's not easy to work out where the problem is.
When you say "It didn't jump to Insert action of QuestionController." do you mean that the browser didn't load that page or that when the url was loaded it didn't route to the expected controller/action?
You could use an iframe if you want to avoid using AJAX, but I would recommend using AJAX
<iframe src="" id="loader"></iframe>
<script>
document.getElementById("loader").src = url;
</script>