Forum Moderators: open

Message Too Old, No Replies

javascript calling php with eval

         

too much information

7:06 am on Mar 4, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Ok, I can call my php file using Javascript and add the result to the head of the page for a typical AJAX type result, but I'm stumped on how to get the result of the php file and evaluating the resulting javascript code immediately.

Here's what I have for my Javascript code:

function loadContent(file){
var xhr;
try { xhr = new ActiveXObject('Msxml2.XMLHTTP'); }
catch (e)
{
try { xhr = new ActiveXObject('Microsoft.XMLHTTP'); }
catch (e2)
{
try { xhr = new XMLHttpRequest(); }
catch (e3) { xhr = false; }
}
}
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4)
{
if(xhr.status == 200)
eval(xhr.responseText);
else
document.ajax.dyn=\"Error code \" + xhr.status;
}
};
xhr.open(GET, file, true);
xhr.send(null);
}

Now the php file returns a strictly javascript result that I need to evaluate once it is returned. But I'm missing something because it's not doing what I expect.

My original javascript simply appends the php result to the head of the document and it works great:

function loadContent(file){
var head = document.getElementsByTagName('head').item(0);
var scriptTag = document.getElementById('loadScript');
if(scriptTag) head.removeChild(scriptTag);
script = document.createElement('script');
script.src = file;
script.type = 'text/javascript';
script.id = 'loadScript';
head.appendChild(script);
}

but adding eval() into that code does not give me the desired result either.

What I'm trying to do is call the javascript from Flash Actionscript and use my Javascript/PHP method to dynamically return the desired result so appending the javascript to the head of the document does not do the trick. Instead I need to get the PHP result and have it run as javascript within the loadContent function.

My typcial PHP result would be something like:

return "some text string";

Any help would be greatly appreciated!

MarkFilipak

7:58 am on Mar 4, 2008 (gmt 0)

10+ Year Member



too_much_information, your code's not very good.

If this is executed: catch (e3) { xhr = false; }
then this: xhr.onreadystatechange = ...
will throw an exception as well.

Regarding your advertised problem...

your eval is going to try to execute in global context but 'this' is the xml http request object. I'm not surprised it doesn't work, though I can't think of why not. Errr... maybe I can.

If the xhr.responseText generated by the PHP does only text-thingies (like setting a global text variable), you're probably OK, but if it tries to access objects or makes a function call, you may have context trouble and those objects or functions may be unreachable -- I have encountered similar problems with event objects. I use Ajax only to pass string arguments to a global, predefined handler function, not scriptlets to the eval function, so I'm afraid I can't be of much more help.

MarkFilipak

8:18 am on Mar 4, 2008 (gmt 0)

10+ Year Member



Hey! The following should work with your original loadContent function...

function getFileURL(){
var xhr;
try { xhr = new ActiveXObject('Msxml2.XMLHTTP'); }
catch (e)
{
try { xhr = new ActiveXObject('Microsoft.XMLHTTP'); }
catch (e2)
{
xhr = new XMLHttpRequest();
}
}
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4)
{
if(xhr.status == 200)
loadContent(xhr.responseText);
else
document.ajax.dyn=\"Error code \" + xhr.status;
}
};
xhr.open(GET, file, true);
xhr.send(null);
}

MarkFilipak

8:49 am on Mar 4, 2008 (gmt 0)

10+ Year Member



I know why your code isn't working.

The key:
My typcial PHP result would be something like:
return "some text string";

So, your eval will be: eval('return "some text string";'), right?

That won't work. Why? Because your call: loadContent(file), puts the call on the call stack. When loadContent ends it's taken off the call stack. Later, when xhr.onreadystatechange runs, there's nothing on the call stack so your eval('return "...";') has nowhere to return the string.

too much information

3:34 pm on Mar 4, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Awesome response Mark!

Yea, I know my code isn't great. I'm not a fan of Javascript so I'm forcing myself to learn something new and this is what I had pieced together from my searches.

Let me play with that, and I'll get back to you. I'm not sure that's the solution I'm looking for but your explanations help a lot. Maybe I'm not understanding my problem enough yet.

MarkFilipak

9:42 pm on Mar 6, 2008 (gmt 0)

10+ Year Member



Hey too_much_information. Do you know that Ajax can be run synchronously? That might be the ticket in your application. Synchronous causes javascript to stall until the HTTP response is received (but I don't know how it does that). Merely leave out the onreadystatechange handler, change the "true" in "xhr.open(GET, file, true);" to "false", and add your processing code after the "send". I've never used synchronous Ajax so I can't be of further help, but googling "synchronous Ajax" and also looking on MSDN should pop up what you need. Let me know how it goes.

[edited by: MarkFilipak at 9:43 pm (utc) on Mar. 6, 2008]

too much information

11:08 pm on Mar 6, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Awesome, I didn't know that. I'll take a look at it to see what it can do. That might be the key to my problem.

Honestly, I could have been done with this project if I wasn't trying to use Flash. The simple Ajax stuff I can do, but trying to return the results as a string for Flash is only one of my problems.

Thanks for the help, I'll see how that works out.

gergoe

12:07 am on Mar 7, 2008 (gmt 0)

10+ Year Member



eval('return "some text string"'); does nothing, it returns the 'some text string' to nowhere. If you want this string to be passed back as a result of your function, you'll need one more return statement:
return eval('return "some text string"');

Even then, it will not work, because the onreadystatechange is not called from the context of flash nor your loadContent function, so returning anything from that event handler does nothing meaningful. It is called asynchronously, while the main flow of the code is passed the point where you called send(). Most probably the eval'd statement is executed after the loadContent() finished running, and the flash already got back the control, so you are returning a value to the void.

If you would switch using to synchronous calling as mentioned by MarkFilipak, that would mean that the send() method will not return the control as long as the xml request is not succeeded (or failed). So immediately after the xhr.send(''), you can start parsing the response, as you do it now in the event handler (but note the double return's, that still applies).

And still, I'm not sure you can return a value to Flash just like this, you might end up finally calling an ActionScript function from the flash movie instead of retuning a value - but then you can again consider sticking to asynchronous calling (because then it does not matter anymore, from what context the ActionScript function is being called), you only need to consider the way your programmed the Flash movie:

  • If it is a problem that it *hangs* for a second or two, then consider using asynchronous calling (that is the AJAX way)
  • If it is a problem that the expected result (the string) is *not* available immediately after calling the JavaScript code, and you can't avoid that, then use synchronous calling

And just a final note, Flash and ActionScript has this out of the box, it is already capable of calling an URL, fetching anything it founds there, and then work with that, I don't think you really need JavaScript, and especially AJAX for this.

MarkFilipak

12:42 am on Mar 7, 2008 (gmt 0)

10+ Year Member



>> Even then, it will not work, because the onreadystatechange ...

Actually, gergoe, that's not true. Unlike an event object, objects returned by the XMLHttpRequest constructor (for which onreadystatechange is a method) DO have global scope. Hence, the loadContent function will be reachable. You can probably confirm this by looking at some of your own code.

The only potentially painful detail that I know of is that in IE (... new ActiveXObject('Microsoft.XMLHTTP') ...), the onreadystatechange method can only return a string, not an object. But since too_much_information only needs a string to feed to flash, I guess that's OK.

I don't get it when you write
return eval('return "some text string"');
I believe that too_much_information is using PHP to prepare some javascript based on the Ajax "GET" which he then simply wants to eval (i.e., execute) - I may be wrong but I don't think a return of the eval'ed expression's result is what's desired.

[edited by: MarkFilipak at 12:52 am (utc) on Mar. 7, 2008]

gergoe

3:47 pm on Mar 7, 2008 (gmt 0)

10+ Year Member



My typcial PHP result would be something like:

return "some text string";

function foo() {eval('alert("hello");');}

...will do what it is supposed to do;

function foo(bar) {eval('return "' + bar + '";');} 
alert(foo('hello'));

...will pop up an empty window, because the return value within the eval'd code is only returns that value to the eval() function, but you still need to return the return value of the eval() function. So evaluating eval('return "foo";') will result in the string "foo", but you still need to pass this on. This situation is quite similar to the way one is supposed to handle the form's onsubmit event handler.

function foo(bar) {return eval('return "' + bar + '";');} 
alert(foo('hello'));

...will behave as the first example.

The onreadystatechange is called with the global scope, so it has access to any globally defined variables indeed, but the context it has been called from, is the xmlhttp object, not the javascript function, so returning a value from onreadystatechange (when called asynchronously) makes less sense.

MarkFilipak

6:11 pm on Mar 7, 2008 (gmt 0)

10+ Year Member



Excellent, gergoe!

I forgot -- or suffered a brain fart -- that too_much_information simply wants to return that string rather than executing it as javascript. The mere presence of an eval instruction triggers "run" in my mind, even if its argument is "return". return eval('return "'+ bar +'";'); is really a roundabout way to do this: return bar; Duh!

gergoe

6:42 pm on Mar 7, 2008 (gmt 0)

10+ Year Member



return eval('return "'+ bar +'";'); is really a roundabout way to do this: return bar;

Indeed a nice roundabout, it's like going from London to Paris with a change in NYC; but as an example it did it well :-)

To get back to the problem of too_much_information; it could be done and simplified in many ways, one of them is to use flash for the whole thing (bypassing javascript). JavaScript is a great tool, but if a problem can be solved in a much simpler manner using an another tool, why to force it upon you? You can check the Flash and Shockwave [webmasterworld.com] forum for more information on how to do this.

too much information

6:23 am on Mar 8, 2008 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



actually gergoe Flash is exactly where I've been looing, although it's tough to find good help online like you can get here at WebmasterWorld with everything else.

Right now I'm looking into Flex Builder. It seems like it may have most of what I need built in and it should save me some time code wise. I'm not far enough along to test anything yet but it looks promising.

As far as the original problem, I can use a simple javascript with a return to get my string (or array) into Flash, but as soon as I try to use PHP to create a dynamically generated Javascript it no longer works. So instead what I did was build my javascript dynamically using PHP and include it as the src in a Javascript tag. It's not exactly what I wanted but it solved the problem for the time being until I realized that returning a PHP generated jpeg results in a smeared image in Flash even if the image is 100px square.

Which is why I'm looking at Flex Builder. I should know by Monday if it's a viable option for what I'm trying to build, but the Flickr project in the beginning tutorial looks promising.

I'm going to have to spend more time reading this Javascript section. It should make my Actionscript learning a little easier.

gergoe

11:50 am on Mar 8, 2008 (gmt 0)

10+ Year Member



Did you tried the Flash and Shockwave [webmasterworld.com] forum of WebmasterWorld regarding this problem (how to read the content of an url and parse it withing flash)?

To make your original work as you intended to do:

[pre]function loadContent(file){
var xhr;
try {
xhr = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {
try {
xhr = new XMLHttpRequest();
} catch (e) {
xhr = false;
}
}
}
[i]//
// Make sure xhr is set[/i]
if (xhr) {
[i]//
// Make the url called synchronously. Execution will be blocked
// until the call did not succeed, so when returning something,
// it will be returned to the caller of loadContent, not the caller
// of the event handler.[/i]
xhr.open(GET, file, [b]false[/b]);
xhr.send('');
if(xhr.status == 200)
[b]return[/b] eval(xhr.responseText);
else {
document.ajax.dyn=\"Error code \" + xhr.status;
return '';
}
}
}[/pre]