javascript quotes inside quotes, string literal issue - php

I am trying to display text in a javascript tooltip
I keep getting unterminated string literals even though:
a) the quotes are being slashed, b) there are no line breaks
The text I am trying to display is:
"No, we can't. This is going to be terrible."
(its a quotation from an individual and I want those quotes to display in the tooltip)
My tooltip function works like this
onMouseOver="Tip('string here')"
After I run the string through my function to clean for javascript
function jschars($str) {
echo preg_replace("/\r?\n/", "\\n", addslashes($str));
}
It comes out looking like this in HTML:
onMouseOver="Tip('\"No, we can\'t. This is going to be terrible.\"')"
This gives me the error unterminated string literal for the first \ in Tip('\
I'm guessing its because im trying to put quotes directly inside the single quotes, how can I get around this for situations like this? (I have tried htmlspecial chars, such as replacing the " with & quot ; - I still get the error

It's because you're putting double-quotes inside the value of an XML (or html) element:
<div onMouseOver="Tip('\".......
the back-slash doesn't escape it from the context of xml/html. Technically, you'll need to entity-encode the string (after you javascript-escape it). Something like this:
<div onMouseOver="Tip('\"No, we can\'t. This is going to be terrible.\"')" >
Various browsers may or may not deal with that properly. A much better way to approach it would be to give the element an id (or a class, or some other way for you to select it), then add the mouse over handler from a standalone script.

Because of the structure of what you're doing:
onMouseOver="Tip('string here')"
...you have to do two things:
As Lekensteyn said, you need to use htmlspecialchars to turn any special HTML characters into character escapes. It does things like turn " into ", which means you can safely enclose the attribute in " characters.
But you're not just using this as an attribute, you're also putting it inside a string literal, which means you also need to do JavaScript escaping on the string. Otherwise, (in your case) a single ' character or backslash will mess up the string. So your jschars function also needs to (in order) A) Convert \ to \\, B) Convert ' to \'. That's the minimum, anyway, really you need a thorough "make this safe to put inside a JavaScript literal" function. From your question, I sort of had the impression you were doing this manually, but better to automate it for consistency.
Off-topic: Separately, I would recommend moving away from using attributes to attach handlers. Instead, look into attachEvent (IE) and addEventListener (W3C), or better yet look at a library like jQuery, Closure, Prototype, YUI, or any of several others that will smooth things out for you. For instance, attaching a mouseover handler to:
You can use this handler to handle the mouseover:
function handler() {
Tip('Your message here');
}
...which you then hook up like this with raw DOM stuff (obviously you'd make a utility function for this):
var div = document.getElementById('foo');
if (div.attachEvent) {
// Uses "onmouseover", not "mouseover"
div.attachEvent('onmouseover', handler);
}
else if (div.addEventListener) {
// Uses "mouseover", not "onmouseover"
div.attachEvent('mouseover', handler, false);
}
else {
// Fallback to old DOM0 stuff
div.onmouseover = handler;
}
Here's how Prototype simplifies that hook-up process:
$('foo').observe('mouseover', handler);
Here's how jQuery does:
$('#foo').mouseover(handler);

You should use htmlspecialchars() for this purpose. The problem is ", but HTML won't understand javascript quoting, so it stops at \".
function jschars($str) {
echo htmlspecialchars(preg_replace("/\r?\n/", "\\n", $str), ENT_QUOTES);
}

You could keep the string in javascript instead of HTML. eg:
<a onmouseover="Tip(this, 123)">choice</a>
Then something like:
var texts = {
123:"No, we can't. This is going to be terrible.",
...
};
function Tip(elm, txtId){
showTip(elm, texts[txtid];
}

Related

Escaping string before assigning to innerHTML echoed by PHP

I'm encountering a problem involving escaping character that I think it's not simple at all. If this is done in javascript, nothing to say but the context is using echo command (in PHP) to write javascript code like this:
echo "<script>document.getElementById('spanID').innerHTML=\"$x\"</script>";
$x is a variable in PHP environment, which can contain both single and double quotes. What I do here is:
1. Keep the $x not change, and if $x contains any double quote, the above code won't work, the text echoed may look like:
<script>document.getElementById('spanID').innerHTML="leftside"rightside"</script>;
I supposed $x = leftside"rightside, and you can see it surely won't work.
Escape the double quotes in $x (change all " to "), then the text echoed may look like this:
document.getElementById('spanID').innerHTML="leftside"rightside";
The " won't be converted to " when it is assigned to innerHTML attribute of a Span (for e.g), so instead of my want, the innerHTML of my SPAN should be leftside"rightside, it will be leftside"rightside.
If I change the " to ' in the original echo, like this:
echo "<script>document.getElementById('spanID').innerHTML='$x'</script>";
It is the same because $x here can contain both single and double quotes.
I don't find out any other ways to escape quotes in this case. Could you please help me out?
Thanks!
You need to put between the quotes a string that is a valid string of JavaScript containing valid (and safe) HTML.
Your best option is to not use innerHTML and instead use document.createTextNode which means you only need to slash-escape the content.
Otherwise, you need to HTML escape, then slash escape the content. For correctness, your slash-escaping function should escape at least double-quotes, backslashes, and all JavaScript newlines (U+A, U+D, U+2028, U+2029). I believe PHP's addslashes does not handle U+2028 or U+2029 by default but How to escape string from PHP for javascript? has some alternatives.
To put it all together:
$x_escaped = json_encode($x, JSON_HEX_TAG);
echo "<script>document.getElementById('spanID').appendChild(document.createTextNode($x_escaped))</script>"
should do it. The JSON_HEX_TAG makes sure that $x_escaped will not contain </script> or any other content that prematurely ends your script tag. </script> will instead become \u003c/script\u003e.

jQuery load function escapes data

I have a strange problem with the load function from jQuery. It escapes HTML content that jQuery gets back from the load function. I load HTML output from a PHP file into a div. I use this function:
function XXX(file,divName,functionToCall)
{
$("#" + divName).load(file,null,function()
{
functionToCall();
});
};
The HTML output of the PHP file:
<div onClick="xxx(0,'xxx')" id="xxx"></div>
Jquery converts it into:
<div onClick="xxx(0,\'xxx\')" id="xxx"></div>
Because of this convention I can't use the onClick function, it isn't valid any more. I can't figure out what I 'm doing wrong, does some one know what causes this problem and how to solve this in a good way? I already read other related question on Stack overflow, but I couldn't find an answer how to avoid escaping.
I guess your problem isn't in a PHP block. Here are some rules you need to follow:
For PHP use these rules:
When to escape the char ' :
When you want to use ' in a ' ' block. For example: echo 'test: \' this workes ';
When you don't need to escape the char ' :
When you want to use ' in a “ ” block. For example: echo “test: '
this workes “;
For HTML use these rules:
If you aren’t in a PHP block, then you don't need to escape data. The data you wrote here will directly be outputted. When you want to make a onClick, just use this template: onClick”functionName('stringValue');”
Maybe it's because of the editor:
Some editors will give \' an other color, don't let the colors distract you. It doesn't mean it's correct! Use a file editor with less features ( like notepad ) and open the PHP file where you were talking about. Check again if there are no \'s on places where they shouldn't be.
The problem isn't JQuery in this case. Trust me, look at the PHP file. Did you maybe escaped data outside a PHP block?
This has something to do with you PHP implementation not javascript. When PHP outputs your html it's set to escape quotes.

Getting all tangled up in json_encode/json_parse and escaping

I have problems when users input " or \ on a html form
The inputted text will be shown again to the user in html content and html attribute contexts
I have the following data flow:
jQuery form line input
$_POST
escape for html attribute: function escapes either with html entities or hex entities (" or \)
json_encode in php
some unknown javascript interference which blows the fuses
json_parse in a jquery ajax callback
The goal is to show the user the exact same text as they inputted, but to escape properly to avoid xss attacks.
Now first thing I got was that $_POST had slashes added for some reason. So I now use stripslashes first. That solved everything for single quotes, but if the user inputs " or \ it still breaks.
The problems seems to be that javascript does some decoding before the json_parse gets the data. it turns the hex escapes back to \ and " thus killing json_parse.
So then I thought if between step 4 and 5 I use htmlspecialchars( $data, NO_QUOTES, 'utf-8' ) I encode the ampersands to &, which should neutralise the javascript decoding, but no. It doesn't decode &for some reason while it does decode &quot and the hex encodings...
Where am I going wrong?
Is there a way to know exactly what the javascipt decodes and neutralize it from php?
What I'm doing now, after wasting half a day:
I think it's probably some jQuery thing to interfere with the data before the onsuccess handler gets it. I have no time to dig it up and kill it right now, so I'm just sneaking past it with a hack that means 3 string transformations just to keep a string untransformed, but hey, developer time is a rare commodity here.
in php:
// due to a problem with the jQuery callback code which seems to decode html entities and hex entities except for &
// we need to do something to keep our data intact, otherwise parse_json chokes on unescaped backslashes
// and quotes. So we mask the entity by transforming the & into & here and back in js.
// TODO: unit test this to prevent regression
// TODO: debug the jQuery to avoid this workaround
//
// echo json_encode( $response );
echo preg_replace( '/&/u', '&', json_encode( $response ) );
in js before parse_json:
// due to a problem with the jQuery callback code which seems to decode html entities and hex entities except for &
// we need to do something to keep our data intact, otherwise parse_json chokes on unescaped backslashes
// and quotes. So we mask the entity by transforming the & into & here and back in js.
// See function xxxxxx() in file xxxxx.php for the corresponding transformation
//
responseText = responseText.replace( /&/g, '&' );
I couldn't be bothered at the moment to write the unit tests for it, but I don't seem to be able to break it.
The true question remains how can I knock out the unwanted transformation while getting the same result?
Try turning off "Magic Quotes" in php. That way the data comes in through $_POST just like the user typed it. See: http://www.php.net/manual/en/security.magicquotes.disabling.php
Then you can escape it according to your needs.
I had a problem like your problem and used utf8_encode() function. Now it works well. Can you try it ?

Unescaping " In PHP Dynamically

There is a page that I'm currently working on (http://www.flcbranson.org/freedownloads-new.php) that loads data from an rss feed.
That rss feed contains descriptions, some of which contain quotation marks.
When the page is displayed (you can click on the Read Summary link for Filled With All The Fullness Of God to see what I'm talking about), it does \" for each quote.
I assume that it's because of php's escaping requirements.
Is there a way that I can remove the escape character (other than the obvious "remove the quotation marks")?
Sounds like you have magic quotes turned on. Read the PHP documentation for stripslashes() and pay special attention to the magic quotes stuff.
In a nutshell, if you know that your working with a string and not (say) an array, you can do the following:
if (get_magic_quotes_runtime()) {
$string = stripslashes($string);
}
If the data is coming from $_GET, $_POST, or $_COOKIE superglobals, use this instead:
if (get_magic_quotes_gpc()) {
$string = stripslashes($string);
}
If it's not a string you're dealing with, you may need to look at the stripslashes_deep() implementation in the PHP docs.
You need to remove the slashes by running data through:
stripslashes()
However, you still want to make your output (if you are doing something with this) HTML safe.
so run this function on the data after:
htmlspecialchars()
try using stripslashes()
http://www.php.net/manual/en/function.stripslashes.php
checkout stripslashes()

Escape brackets on php for javascript

For example i've a php script with this content:
<?php
$msg = addslashes("I'm a message. The what happened >:(");
echo "<script>alert($msg); return false;</script>";
?>
But the alert get broken by the last "(". How can i solve this?
You should enclose alert parameter with quotes:
echo "<script>alert('$msg'); return false;</script>";
What your code outputs to the browser was:
<script>alert(The what happened >:(); return false;</script>
which is not a valid javascript, after putting the quotes, it becomes:
<script>alert('The what happened >:('); return false;</script>
which is valid javascript.
You need to put it in a JavaScript string, otherwise it gets interpreted like this, which is meaningless and causes an error:
<script>alert(The what happened >:(); return false;</script>
Notice the single quotes in the alert() call which denote a JavaScript string (double quotes work too):
<?php
$msg = "The what happened >:(";
echo "<script>alert('$msg'); return false;</script>";
?>
It is also a good idea to escape the content inside to mitigate XSS, using htmlspecialchars().
The other answers are along the right lines, but it is not sufficient to just put quotes around the string, if it can be any arbitrary string. If the string itself contains a quote, backslash, or newline, that will break the JavaScript string literal. If the string contains </script (or just </ in some cases) that will break the <script> block. In either case, if user-supplied input is involved, that gives you a big old cross-site-scripting security hole.
Whilst you may not need it for this specific value of $msg, it's a good idea to get used to JS-string-literal-escaping any text you output into a JS string. Whilst you can do this manually by adding backslashes, it's generally much easier to just use the built-in JSON encoder, which will work for other types like arrays and objects as well as strings.
<script type="text/javascript">
alert(<?php echo json_encode($msg); ?>);
return false; // huh? return, in a <script> block??
</script>
alert() accepts a string argument; you must enclose the text you're passing to it in quotes (either single or double) and insure that any matching quotes within the string are escaped by backslashes.
In your case single quotes would suffice:
echo "<script>alert('$msg'); return false;</script>";
Depending on the context, you might also just do:
<?php
$msg = "The what happened >:(";
?>
<script>alert("<?php echo $msg ?>"); return false;</script>
If there is no need to echo HTML or JavaScript code, then don't do it. It is easier to maintain .

Categories