Using blade inside of javascript function when the output should be HTML - javascript

The issue I'm having is with escaped html inside of a javascript function, passed from blade. $message contains basic html or strings with quotes, so if I use {!! !!} it doesn't work because it seems that the output from blade into the function needs to be in quotes.
Inside javascript script tag
#foreach ($messages as $message)
addMessages('{{$message['message']}}', '{{$message['message_side']}}');
#endforeach
addMessages javascript function
addMessages = function (text, message_side) {
var $messages, message;
if (text.trim() === '') {
return;
}
$('.message_input').val('');
$messages = $('.messages');
message = new Message({
text: text,
message_side: message_side
});
message.draw();
return $messages.animate({ scrollTop: $messages.prop('scrollHeight') }, 300);
};

So I believe the issue is in double-escaping: first data is escaped by Blades with calling htmlspecialchars()(according to docs) and later it's escaped somewhere in JS code(it may not be escaped directly rather threated as a text through createTextNode(message) or innerText = message).
So you need to turn one of these escape calls off.
As you mentioned you could use { !! } to output raw text on Blade side. And yes, this still needs to be wrapped with quotes(single or double) to be valid JS code. But you should care about the-same-type-quotes(single or double) inside you text to omit such a case:
addMessage('It's me. I'm broken')
To achieve that you can just escape approrpiate quote mark manually with a slash to get something like
addMessage('It\'s me. I\'m broken')
[UPD] as #Ian Fain mentioned it's possible to call functions right inside the { !! }
So finally this escaping can be done without any custom directive as easy as
#foreach ($messages as $message)
addMessages({!! json_encode($message['message']) !!}, {!! json_encode($message['message_side']) !!})
#endforeach
Also mention json_encode adds additional double quotes so they are not needed to be inserted directly anymore.

Related

Properly escape javascript object

Given an object: {"key":"pairs","are":"fun"} that is echoed into a variable like const foo = <?php echo $bar ?>;. What is the proper way to escape the object? I've tried encode_json which escapes all the double quotes {\"key\":\"pairs\",\"are\":\"fun\"} disallowing the object to render. I have also tried esc_js which converts the double quotes to & quot;. How do i properly escape the object and return the object to foo? The out should be {"key":"pairs","are":"fun"} escaped of any malicious content.
If you use wp_json_encode to produce the JSON string itself, the output where you assign the JSON to a JavaScript variable in the browser should be reasonably safe. The wp_json_encode function will escape the characters that might otherwise allow someone to inject code at the point of assignment.
However, you also have to consider how your values in the key/value pairs will be used. If you're expecting an integer, maybe run the value through intval or if you are expecting plaintext that you're injecting into the page later, perhaps run it through esc_html.
For example:
<?php
$map = [
'key' => 'pairs',
'are' => '"; I document.write(\'fun trying to break out\')',
'i_am_expecting_plaintext' => esc_html('Hello<script>evilscript();</script>'),
'i_expect_an_integer' => intval("90i"),
'some_html_allowed' => wp_kses('here<script>dangerous();</script>', ['a' => array('href'=>array())]),
];
?>
<script>const foo = <?php echo wp_json_encode($map, JSON_PRETTY_PRINT); ?>;</script>
Produces the following output:
<script>const foo = {
"key": "pairs",
"are": "\"; I document.write('fun trying to break out')",
"i_am_expecting_plaintext": "<a href="evillinkhere">Hello<\/a><script>evilscript();<\/script>",
"i_expect_an_integer": 90,
"some_html_allowed": "<a href=\"http:\/\/nisamerica.com\/\">here<\/a>dangerous();"
};</script>
Addendum:
The reason wp_json_encode was giving you {\"key\":\"pairs\",\"are\":\"fun\"} before is that you were providing it a string that was already in JSON-notation. What wp_json_encode does is take native PHP variables and escape them as JSON. It's a pretty thin wrapper around json_encode really. My suggestion above is really to just produce the map in PHP, and feed that to the encode function instead of making your string representation and then trying to make it safe.

Dealing with javascript function which processes strings that include quotes

So, essentially I have a button being created in PHP, which runs a JavaScript function, for example
function CreateText(id, string){
alert(id + '' + string);
}
So the PHPcode looks like this
echo "<img onclick='CreateText(3,\"$userinput\")'>";
Where user input is coming from a text box. But, whenever the user inputs a string which contains quotation marks, it throws an error.
Any idea how to fix this?
You're trying to create a valid Javascript literal inside an HTML attribute. For the Javascript, use json_encode, to make that a valid HTML attribute, use htmlspecialchars:
$onclick = sprintf('CreateText(3, %s)', json_encode($userinput));
printf('<img onclick="%s">', htmlspecialchars($onclick));
See http://php.net/sprintf, http://php.net/printf, http://php.net/json_encode, http://php.net/htmlspecialchars.

Javascript syntax error when printing HTML as string from PHP

From within PHP, I want at a certain point to change the content of a DIV called "menu".
In PHP, I do the following:
echo "<script> document.getElementById(\"menu\").innerHTML = \"NewContent\"; </script>";
And it perfectly works.
Then, things get more complicated, and I have a function that "creates" a piece of HTML, like this:
function createNewDiv() {
$o = "Click 'here'";
$o. = "<i onclick=\" $(\"#maindiv\").load('another.php'); return false; \">XXX</i>";
$o .= "<b>... and much, much more...</b>";
return $o;
}
In another area of the page, I do:
echo createNewDiv();
and it prints nicely, no syntax error whatsoever.
If I now try to do something like this:
echo "<script> document.getElementById(\"menu\").innerHTML = \"".createNewDiv()."\"; </script>";
it stops working with some syntax error (from the browser) due to strings that are interrupted "somewhere" by some quotes/double quotes.
I guess I must escape the quotes/double quotes somehow, I tried with addslashes() but it did not work.
Then I realized I only needed to escape the double quotes, so I did
$escaped = str_replace("\"", "\\\"", createNewDiv());
echo "<script> document.getElementById(\"menu\").innerHTML = \"$escaped\"; </script>";
But still it doesn't work! I know it's a truncated string somewhere, but unfortunately I cannot access the source because it's in an AJAX-updated div and the browser only shows me the main page.
I am just going mad thinking about the first function output, going into the str_replace, then into innerHTML, then printed by PHP, then interpreted by the browser... And I get lost "where" the quotes should be escaped ;)
You have nested double-quotes in:
$o. = "<i onclick=\" $(\"#maindiv\").load('another.php'); return false; \">XXX</i>";
It outputs:
<i onclick=" $("#maindiv").load('another.php'); return false; ">XXX</i>
Replace inner double quotes (around #maindiv) with single quotes:
<i onclick=" $('#maindiv').load('another.php'); return false; ">XXX</i>
or replace nested double-quotes with the " entity:
<i onclick=" $("#maindiv").load('another.php'); return false; ">XXX</i>
To make such replacement automatically, use the PHP's built-in htmlspecialchars() function.
By the way, during debug, it's generally a good idea to separate client side from server side. First make static HTML working, then convert it to a server-side scripted one. And consider using a template engine instead of hardcoding HTML into PHP code.

Generate JSON array

I want to generate a JSON array with PHP, but it doesn't work well.
My PHP array looks like this:
protected $resultArray = array("1.0" => 0, "1.3" => 0);
then I do this:
return json_encode($resultArray);
but then i've got this:
var array = [{"1.0":2,"1.3":1}];
Why is " replaced with "?
quot; is a quote character (") encoded as HMTL. json_encode() does not produce HTML encoded sequences.
Replace return with echo in return json_encode($resultArray); and you'll see this for yourself.
Most probably the returned string is passed further to a function that runs it through htmlspecialchars() or htmlentities() and this is the correct way to work with it if you put it into an HMTL context.
Use a different viewer class if you need to output only the json_encode()-ed string. I don't know TYPO3 but I guess you should use JsonView; pass it $resultArray as-is and it will call json_encode() for you.
I think you may using etended library for example in wamp server I tested this code and it's work fine
$str = "<div style='position:relative'><img src='/assets/ui/success.png' /><span
style='position:relative;top:-15px;'>Nachricht empfangen!</span></div>";
echo json_encode(array('prompt' => $str));
//output
//{"prompt":"<div style='position:relative'><img src='\/assets\/ui\/success.png' \/><span style='position:relative;top:-15px;'>Nachricht empfangen!<\/span><\/div>"}
Thanks guys for help!
The solution is (only for typo3). To get a properly correct JSON-Array in the view the JS code has to be improved the following way:
var array = {f:format.htmlentitiesDecode(value:chartarray)};

JSON from Newtonsoft to JavaScript

So, I have a some json data which I create in my controller like so:
Notes = JsonConvert.SerializeObject(contact.Notes.OrderBy(x => x.DateLogged).Select(x => new
{
id = x.Id,
date = x.DateLogged,
content = x.Content,
logged = x.Username
}))
This then gets passed to the view, now which statment can I do to achieve the results of having a variable contain that json data:
var data = '#Html.Raw(Model.Notes)'
or
var data = JSON.parse('#Html.Raw(Model.Notes)');
EDIT
the content variable holds some "\n" which when passed to the view using the first choice from above generates an error, saying
Unexpected Token
it only does it with \n so what is going wrong here? the bottom method doesn't quite work.
var data = JSON.parse('#Html.Raw(Model.Notes)');
This doesn't work - you can't put a JSON literal inside a JavaScript string. Any backslash in it will be an escape character to the JavaScript parser, not the JSON parser. A newline comes out like:
var data = JSON.parse('{"content": "abc\ndef"}');
which means the string you are asking JSON to parse is:
{"content": "abc
def"}
which is not valid as you can't have a literal newline in a JSON string.
To do this with JSON.parse you would have to JS-string-literal encode the JSON output, so you would end up with "abc\\ndef". The alternative would be to include the JSON directly in the script block as var data = #Html.Raw(Model.Notes);, but there are problems with this to do with the differences between JS and JSON (primarily characters U+2028 and U+2029) and the enclosing HTML context (ie what the sequence </script does).
Getting the escaping right here is harder than it looks, so you should avoid injecting anything into a <script> block. Better to put in-page JSON data in a data- attribute and read it from the DOM; this way you can use the normal HTML escaping Razor gives you by default.
<div id="notes" data-notes="#Model.Notes">
...
var data = JSON.parse(document.getElementById('notes').getAttribute('data-notes'));
bobince is obviously correct in what he says, it makes so much sense, thanks for that.
However, my solution was to simply do:
var data = #Html.Raw(Model.Notes);
Because, Newtonsoft already has converted it to a proper JSON format, so all it needs to do, is be assigned to a variable to be manipulated.
I think grabbing the content from a the HTML DOM is a bit too much for this.

Categories