-4

I have a simple test shown below. It works fine, but for some reason the word "undefined" is appearing in the popup. Nothing is leading me to understanding what is undefined. Has anyone experienced this before?

HTML

<html><head>
<style>#popup{border:1px solid black;background:#eadcce;padding:10px;margin:35px;display:none;}</style>
<script>
function popup(){
    var z;
    if(window.XMLHttpRequest){z=new XMLHttpRequest();}else{z=new ActiveXObject("Microsoft.XMLHTTP");}
    z.onreadystatechange=function(){if(z.readyState==4&&z.status==200){
            if(z.responseText != ''){
                    document.getElementById('popup').innerHTML=eval(z.responseText);
                    document.getElementById('popup').style.display="block";
            }
    }}
    z.open("POST",'/test2.php');z.send();
}
</script></head><body>
Push the button to open the popup: <button onclick="parent.popup();">Open Popup</button>
<div id="popup"></div>
</body></html>

test2.php

console.log("test");

Everything works great except the word "undefined" appears in my popup. Does anyone know why? I'm using Firefox 55.0.3.

JBH
  • 1,823
  • 1
  • 19
  • 30
  • `eval` executes javascript code. I think you are looking for `JSON.parse` – JDB Oct 11 '17 at 20:57
  • 2
    Possible duplicate of [what does eval do and why its evil?](https://stackoverflow.com/questions/18269797/what-does-eval-do-and-why-its-evil) – JDB Oct 11 '17 at 20:57
  • `var a = console.log('foo'); console.log('a ->', a);` – Kevin B Oct 11 '17 at 20:58
  • @KevinB i like using the shortcut: `console.log({ a });`. –  Oct 11 '17 at 21:05
  • @KevinB, that doesn't solve my problem. The word "undefined" still appears in my popup. – JBH Oct 11 '17 at 21:07
  • The code you are evaling evals to `undefined`. therefore `undefined` is being assigned to `document.getElementById('popup').innerHTML`, thus causing your modal to display the text `undefined`. it's doing exactly what you are instructing it to do. My code snippet confirms that by showing you that `console.log('foo')` returns `undefined`. – Kevin B Oct 11 '17 at 21:07
  • @Amy, that is not part of my question. – JBH Oct 11 '17 at 21:08
  • @KevinB, ostensibly, simply evaluating `var a=console.log("test");` would remove the "undefined," but it didn't. – JBH Oct 11 '17 at 21:09
  • 1
    haha. no, you're missing the point. – Kevin B Oct 11 '17 at 21:10
  • `function foo() { doSomething();}` for example, when called, returns `undefined`. evaling `foo()` will result in `undefined` being returned. – Kevin B Oct 11 '17 at 21:11
  • @KevinB, that's why I'm asking the question. I'm not understanding something. The actual code from which this example was derived works perfectly... other than printing "undefined" as the first row of text. It appears everything evaluates as "undefined." – JBH Oct 11 '17 at 21:11
  • 1
    Because what you're evaluating has no return value. Not complicated. –  Oct 11 '17 at 21:12
  • Note that only you can see the duplicate banner, and i agree that it is an incorrect duplicate. not much we can do about it unless it ends up closed. – Kevin B Oct 11 '17 at 21:22
  • No, `eval` is not evil... if you read the question you'll see that there are several resources it links to talking about when eval is not evil. Are you seriously executing arbitrary code returned by a service? `eval` returns whatever the last statement in the string evaluates to. `eval('10')` returns `'10'`. `eval('var x = 10')` returns `undefined`. – JDB Oct 11 '17 at 21:23
  • 1
    that's unrelated to the question JDB. – Kevin B Oct 11 '17 at 21:24
  • Though, I would suggest not using eval in this case. it simply isn't needed, change the php to just return the string you want rather than console.log and then eval will not be necessary. You can still then use console.log to log it if you want directly within the javascript. – Kevin B Oct 11 '17 at 21:25
  • @KevinB, regrettably, this is only a test case to demonstrate the problem. I actually do need to execute Javascript returned to the popup. If there's a way to do it without using `eval()` or first saving the script to a file, I'm very interested to know what it is. – JBH Oct 11 '17 at 21:27
  • Ah, if your php is returning javascript, then yes your only options are appending a script tag, or eval. If appending a script tag, the method would need to change from POST to GET, and at that point it would simply replace the ajax request altogether. – Kevin B Oct 11 '17 at 21:28
  • @KevinB, I have no objection changing from POST to GET, where can I learn more about that solution? – JBH Oct 11 '17 at 21:29
  • Chill man... the duplicate question explains what `eval` does. That was the point. I have no opinion on whether or not `eval` is evil (it's quite handy in some scenarios, and I have no wish to make an argument to W3 that it be removed)... that said, you should know it has potentially severe consequences, which the linked question covers. And yes... eval executes arbitrary code, and you are getting that code *from a service*. That's quite dangerous, but if you know what you're doing then it's acceptable. – JDB Oct 11 '17 at 21:29
  • 1
    `var s = document.createElement('script'); s.src = '/test2.php'; codeThatAppendsToHeader(s);` for example. all you'd be doing is creating a script tag and appending it. however, you wouldn't be able to read it's contents to get the modal text, you'd have to obtain it some other way such as calling a function within the returned js – Kevin B Oct 11 '17 at 21:30
  • 1
    Setting the src of a script tag is a good idea, as @KevinB recommends. You may need to change the response type of your PHP page, though, as an incorrect MIME type (e.g. `text/html`) could cause some browsers to get confused. – JDB Oct 11 '17 at 21:36
  • The only difference between `eval`-ing network-supplied code versus inclusion via ` – apsillers Oct 11 '17 at 21:50
  • @apsillers - That's not the only difference. `eval` tends to be much faster, but using a script tag makes debugging significantly easier. Also, [eval falls afoul of certain CSP rules](https://developer.chrome.com/extensions/contentSecurityPolicy#JSEval), which may or may not be significant. – JDB Oct 11 '17 at 22:20

1 Answers1

2

eval evaluates JavaScript code and returns the result of the last statement evaluated. The function console.log returns undefined, so eval('console.log("test")') also returnsundefined(after printing the stringtest` to the browser's log).

If you don't want your dialog to include undefined, don't make the last stement in your evaluated JavaScript string be a call to a function that returns undefined. For example, the string

console.log("test"); "foobar";

will return the string foobar when evaluated with eval, since that's the value of the last statement.

Similarly, the string

console.log("test"); ['a', 'b'].indexOf('a');

will return 0 when evaluated, because that's the returned value of the indexOf call in the final statement.

apsillers
  • 112,806
  • 17
  • 235
  • 239