sixohthree.com

Escaping JavaScript for PHP

Inline JavaScript can be hard to code around with PHP. There’s a lot going on in an onClick handler, and quoting can be a huge problem. Lots of time you have a snippet like this:

<a href="#" onClick="doFunction('<?php echo $myVar; ?>')">

Imagine all the possibilities: what if $myVar contains a single quote character? A double quote? A double quote, followed by some HTML tags? There are workarounds for escaping JavaScript using PHP, but mostly inside <script> tags.

Well, here’s a sure-fire PHP function to encode any ASCII string:

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;
}

So, let’s use this function in our link:

<a href="#" onClick="doFunction('<?php echo javascript_escape($myVar); ?>')">

Let’s say we have the assignment $myVar = "&?1xc'\"". The user-agent ends up with this link:

<a href="#" onClick="doFunction('\x26\x3f\x31\x78\x63\x27\x22')">

The string is ultra-sanitized, and your function gets the string you intended. You may wish to write another function that only escapes target characters, possibly single quote, double quote, and ampersand. I’ll go with overkill for now.

Posted 2004-08-27 at 20:28
Categories Personal
Tags
Short URL http://sixohthree.com/241
Canonical URL http://sixohthree.com/241/escaping

20 Comments

  1. That was a great tip, cause i couldn’t find any solution how to add single and double quotes to onClick attribute from php. Normal usage didn’t just work. Thanks. I used that tip (your function) on a messanger class, where i “trace” userlist and when user clicks some name from the userlist, that name should appear on message box. Messanger is made with php-mysql-js and works quite well on IE. Other browsers may have some issues…

  2. naiad says:

    i’m using this function but when i do it javascritp only displays hte hex.

    am i missing a step?

  3. naiad,

    Sorry for the confusion. WordPress stripped out the backslash character in some of my code. The correct JavaScript escape sequence for hex is \x.

  4. Aaron says:

    I am also getting the same results as Naiad, what do i need to do in JS to convert this back to a readabe string?

    thanks!
    Aaron

  5. Aaron says:

    Please disreguard my last post, this was occuring in the html text because i encoded the variable for the link, as well as the actual node value.

    Many thanks for your time!

  6. I think this function does not work for UTF-8 pages. If you know someone that does, please let me know to my email! Thanks!
    Jose.

  7. Joseph says:

    Why not just have PHP escape it?

  8. Joseph,

    Could you elaborate?

  9. Jason says:

    Sir, i need more sample pls

  10. Blech says:

    function javascript_escape($str) {
        $new_str = ”;

        for($i = 0; $i < strlen($str); $i++) {
            $val = ord(substr($str, $i, 1));
            $prefix = $val < 16 ? ‘\\x0′ : ‘\\x’;
            $new_str .= $prefix . dechex($val);
        }

        return $new_str;
    }

  11. Blech says:

    This one handles newlines and tabs. ^ There should be a preview button here!

  12. Jake Cebula says:

    Guess who stumbled upon this useful post :) Not the first time you’ve helped me out, old friend. Thanks!

  13. Pascal says:

    Why not just use addslashes($myvar)?

  14. Pascal,

    Here’s an example of addslashes() allowing XSS. It’s not sufficient to block all hack attempts. That page will load off-domain JavaScript in Firefox 3.0.1, Opera 9.51, Safari 3.1.2, and Internet Explorer 7.0.6001.18000.

  15. Pascal says:

    I see. And I guess using htmlentities(strip_tags($myVar)) would break the javascript. Good script then.

  16. tedivm says:

    You should take the “strlen($str)” check and put it outside of the for loop. The reason is that function calls use up a lot more resources than simple variable checks, and where the strlen function currently is it will be called for each interation of the loop (so if the string has a length of 50, that function will be called fifty times).

    $strLen = strlen($str);
    for($i = 0; $i < $strLen; $i++) {
        $new_str .= ‘\\x’ . dechex(ord(substr($str, $i, 1)));
    }

  17. tedivm: good point. I’ve updated the post to reflect your suggestion.

  18. Nightfly says:

    For super tidy string iteration, I always use this:

    for($i = 0, $l = strlen($str); $i < $l; $i++) {
        $new_str .= ‘\\x’ . dechex(ord(substr($str, $i, 1)));
    }

  19. JN says:


    function js_escape($str) {
            for($i = 0, $l = strlen($str), $new_str=''; $i < $l; $i++)
                    $new_str .= (ord(substr($str, $i, 1)) < 16 ? '\\x0' : '\\x')
                            . dechex(ord(substr($str, $i, 1)));
            return $new_str;
    }

Respond

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>