Best ajax questions in November 2011

login implementation in PHP/MySQL/Apache

9 votes

i am building a new site where a user can login. i have 3 options here:

1) classic:

<form action="/login.php" method="POST">

</form>

and the submit button goes to login.php and validates and redirects if success

2) ajax:

same as above but do an ajax call instead and then the javascript redirects

3) iframe:

same idea as stackoverflow/openid

i am wondering which one is better and more secure? thanks

well, in my opinion options 1 & 2 should use post, and in your code you should make sure the request is post. you should also add in other session logic against spoofing if you want the application to be super secure, but this is preferential to the developer and the application. i find iframes to be evil and many hackers use iframes to hack unknowing user's accounts. openid is a trustworthy way to login and is becoming more widely adopted, as well as the facebook version of openid. i know they use the iframe method, but verification is doubled and i believe https is required to implement these type of logins.

again all of this is just my opinion and mostly reliant on the developer's design and business needs/requirements of the application.

hope this helps :)

What are some best practices for client-server interaction?

7 votes

I'm building a website for work, and one of the more important features is a rich content grid displaying data. By default, it only displays 20 items per page, but we have ~200 items in the database that can be filtered, sorted, and searched.

Our sales and marketing team has also requests a "list all" feature so they can display all of the data in one place and scroll through rather than page through the data.

Flexigrid data

This entire system is built using ASP.Net MVC on the server side, jQuery and Flexigrid on the client side, and uses JSON to exchange data between the two via AJAX.

I've gotten the actual data transfer part pretty solid. A page of 20 results takes 800ms for the entire request (POST a request to the server via Flexigrid and get the response). It's more the client-side processing that takes a while.

I could offload some of the client-side processing to the server. But this would make the server-side operation take longer and make the size of the document returned that much larger. Not a problem in situations with a high-speed Internet connection ... but that's not necessarily the case.

The other option I have is to download as much data as possible and shift the majority of the data processing to the client. This cuts the request time down to basically nil (only fetching changed elements rather than the entire data set). It will work pretty well on machines with fast CPUs and a lot of RAM, but that's not necessarily the case, either.

Since at least one person flagged this as "not a real question," let me clarify ...

  • What can I possibly do to alleviate the client-side processing time issues without moving so much processing to the server that I end up with a data transfer time issue?
  • What are some best practices when it comes to balancing client-side processing with server-side processing?
  • Is it better to err on the side of the server or the client?
  • What are some tools I can use to better optimize these exchanges so that things don't continue to go awry?

What are you processing on the client side that is taking so long? Processing a JSON object (even a very large one) should not be too intensive.

A lot of DOM look ups when writing your data client side could slow things down. Reducing DOM lookups can greatly help performance. I believe good practice for balancing server & client side processing is to error on the server. Since the server is under your control you can always choose to upgrade your server. Keeping the majority of processing on the server will also make things easier for mobile devices and older computers.

You should utilize AJAX & client side capabilities in a way that enhances the user experience. Load and process data as it is requested by the users. By loading only what they request you can decrease the load on your server & client.

If you are also requesting the same sort of data over and over you can look in to both server & client side caching. By utilizing caching you can reduce request times and/or bandwidth.

jQuery ajax this.id undefined

7 votes

I have a list of items I delete using AJAX.

This list is a simple list with divs and each div as an id so when the item is removed from the database I return true and then it removes the line.

Here my code:

HTML

<div id="row1">
<div>item1</div>
<div><a href="...">view</a></div>
<div><a id="1">delete</a></div>
</div>

JS

$('.delete').click(function () {
    if (!confirm('Are you sure you want to delete?')) {
        return false;
    }
    $.ajax({
        type: "POST",
        url: '/delete_record',
        data: 'id=' + this.id,
        cache: false,
        success: function (result) {
            if (result == 'good') {
                $('#row' + this.id).remove();
            }
        }
    });
});

For some reason the this.id does not work because this.id is undefined ... why? I have id="1" on my a href.

The this you are using refers to the ajax object because there is a new scope within that function. If you want to access variables outwide your scope, you have to declare them before the ajax call.

$('.delete').click(function () {
    if (!confirm('Are you sure you want to delete?')) {
        return false;
    }
    var _this = this;
    $.ajax({
        type: "POST",
        url: '/delete_record',
        data: 'id=' + this.id,
        cache: false,
        success: function (result) {
            if (result == 'good') {
                $('#row' + _this.id).remove();
            }
        }
    });
});

How do I dynamically insert an SVG image into HTML?

6 votes

I have some code that retrieves a scripted svg image from a server via Ajax. I can get the image text back into the browser, but I can't find a way to insert it into the DOM that will actually display it. Can anyone help with this? The svg looks likes this:

<svg id="chart" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="init(evt)">
<script type="application/ecmascript">
<![CDATA[
...lots of code, changes on each Ajax request
//]]>
</script>
<script type="application/ecmascript" xlink:href="js-on-server-1.js"/>
<script type="application/ecmascript" xlink:href="js-on-server-2.js"/>
</svg>

I've tried various things. If I do this:

// xmlhttp.onreadystatechange:
addImage(xmlhttp.responseXML, "somewhere");
...
function addImage(txt, dst_id) {
   var scr = document.createElement("div");

   if("textContent" in scr)
      scr.textContent = txt;  // everybody else
   else
      scr.text = txt;         // IE

   document.getElementById(dst_id).appendChild(scr);
}

Then Opera and Chrome do nothing, and F/F complains "[object XMLDocument]". If I change 'responseXML' to 'responseText', then Opera/Chrome correctly display the entire svg text (not image) in the right place, and F/F still gives the same warning. I've also tried assigning the response to an innerHTML, but that does nothing. Any ideas? Thanks.

EDIT

In response to Phrogz'z answer below - I've added two simple svg files. The first is a 'standard' simple svg, displaying a circle. The second is a scripted svg, displaying a rectangle. You should be able to view both directly in any browser, except IE8-. If I edit Phrogz'z code to use the circle file (replace 'stirling4.svg' with the name of this file), then it works, but if I want the scripted rectangle instead, it doesn't. Tested on F/F, Opera, Chromium, but doesn't work anyway on (my) Chromium.

File 1, circle:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
</svg>

File 2, rectangle:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="init(evt)">
<script type="application/ecmascript">
<![CDATA[
var svgDocument;
var svgns = "http://www.w3.org/2000/svg";
function init(evt) {
  if(window.svgDocument == null)
    svgDocument = evt.target.ownerDocument;
   var lbox = svgDocument.createElementNS(svgns, "rect");
   lbox.setAttributeNS(null, "x",                10);
   lbox.setAttributeNS(null, "y",                10);
   lbox.setAttributeNS(null, "width",            30);
   lbox.setAttributeNS(null, "height",           30);
   lbox.setAttributeNS(null, "stroke",           "#8080ff");
   lbox.setAttributeNS(null, "stroke-width",     2);
   lbox.setAttributeNS(null, "fill-opacity",     0);
   lbox.setAttributeNS(null, "stroke-opacity",   1);
   lbox.setAttributeNS(null, "stroke-dasharray", 0);
   svgDocument.documentElement.appendChild(lbox);
}
//]]>
</script>
</svg>

Presumably the answer is to get the script into the header??

In general, the problem is twofold threefold:

  1. HTML is not XHTML, and support for SVG in HTML is shoddy and poorly-defined as of this writing. The solution is to use a real XHTML document where SVG-namespaced elements are actually treated as SVG.

  2. The responseXML is in another DOM document, and you can't normally just move nodes from one document to another. You are supposed to use document.importNode to import a node from one document to another.

  3. Loading an SVG file with onload event handlers will not have those handlers invoked by either creating the node or appending it to the document. Code inside the script block will be run, however, so you need to rewrite your scripts in a manner that works standalone and also with the dynamic loading.


Here's a simple example that works in Chrome, Safari, and Firefox...but not IE9:

var xhr = new XMLHttpRequest;
xhr.open('get','stirling4.svg',true);
xhr.onreadystatechange = function(){
  if (xhr.readyState != 4) return;
  var svg = xhr.responseXML.documentElement;
  svg = document.importNode(svg,true); // surprisingly optional in these browsers
  document.body.appendChild(svg);
};
xhr.send();

See it in action here: http://phrogz.net/SVG/import_svg.xhtml


Unfortunately IE9 does not properly support document.importNode. To work around this, we write our own cloneToDoc function that creates an equivalent structure for any given node by recursively crawling the hierarchy. Here's a full working example:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head> 
  <meta http-equiv="content-type" content="application/xhtml+xml;charset=utf-8"/>
  <title>Fetch and Include SVG in XHTML</title>
  <script type="text/ecmascript"><![CDATA[
    setTimeout(function(){
      var xhr = new XMLHttpRequest;
      xhr.open('get','stirling4.svg',true);
      xhr.onreadystatechange = function(){
        if (xhr.readyState != 4) return;
        var svg = cloneToDoc(xhr.responseXML.documentElement);
        document.body.appendChild(svg);
      };
      xhr.send();
    },1000);
    function cloneToDoc(node,doc){
      if (!doc) doc=document;
      var clone = doc.createElementNS(node.namespaceURI,node.nodeName);
      for (var i=0,len=node.attributes.length;i<len;++i){
        var a = node.attributes[i];
        if (/^xmlns\b/.test(a.nodeName)) continue; // IE can't create these
        clone.setAttributeNS(a.namespaceURI,a.nodeName,a.nodeValue);
      }
      for (var i=0,len=node.childNodes.length;i<len;++i){
        var c = node.childNodes[i];
        clone.insertBefore(
          c.nodeType==1 ? cloneToDoc(c,doc) : doc.createTextNode(c.nodeValue),
          null
        ); }
      return clone;
    }
  ]]></script>
</head><body></body></html>

See it in action here: http://phrogz.net/SVG/import_svg_ie9.xhtml


Edit 2: As suspected, the problem is that the onload event does not fire when dynamically adding script. Here's a paired solution that works:

  1. Rewrite your script to remove the onload event handler. Instead, trust that document exists.
  2. Rewrite your script to ask for a global svgRoot; if it doesn't exist, use document.documentElement.
  3. When fetching the SVG set a global svgRoot to the new svg element after you import it into the document.

Here's the code in action:

And, in case my site is down, here is the code for posterity:

script-created.svg

<svg xmlns="http://www.w3.org/2000/svg">
  <script type="text/javascript"><![CDATA[
    function createOn( root, name, a ){
      var el = document.createElementNS(svgNS,name);
      for (var n in a) if (a.hasOwnProperty(n)) el.setAttribute(n,a[n]);
      return root.appendChild(el);
    }
    // Trust someone else for the root, in case we're being
    // imported into another document
    if (!window.svgRoot) svgRoot=document.documentElement;
    var svgNS = svgRoot.namespaceURI;
    createOn(svgRoot,'rect',{
      x:10, y:10, width:30, height:30,
      stroke:'#8080ff', "stroke-width":5,
      fill:"none"
    });
  ]]></script>
</svg>

import_svg_with_script.xhtml

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head> 
  <meta http-equiv="content-type"
        content="application/xhtml+xml;charset=utf-8" />
  <title>Fetch and Include Scripted SVG in XHTML</title>
  <script type="text/ecmascript"><![CDATA[
    setTimeout(function(){
      var xhr = new XMLHttpRequest;
      xhr.open('get','script-created.svg',true);
      xhr.onreadystatechange = function(){
        if (xhr.readyState != 4) return;
        var svg = xhr.responseXML.documentElement;
        svg = cloneToDoc(svg);
        window.svgRoot = svg; // For reference by scripts
        document.body.appendChild(svg);
        delete window.svgRoot;
      };
      xhr.send();
    },1000);
    function cloneToDoc(node,doc){
      if (!doc) doc=document;
      var clone = doc.createElementNS(node.namespaceURI,node.nodeName);
      for (var i=0,len=node.attributes.length;i<len;++i){
        var a = node.attributes[i];
        if (/^xmlns\b/.test(a.nodeName)) continue; // IE can't create these
        clone.setAttributeNS(a.namespaceURI,a.nodeName,a.nodeValue);
      }
      for (var i=0,len=node.childNodes.length;i<len;++i){
        var c = node.childNodes[i];
        clone.insertBefore(
          c.nodeType==1 ? cloneToDoc(c,doc) : doc.createTextNode(c.nodeValue),
          null
        )
      }
      return clone;
    }
  ]]></script>
</head><body></body></html>

symfony 2 equivalent for url_for() function in symfony 1

6 votes

In Symfony 1 we can access an action in template page as for example url_for('modulename/actionname') without writing anything in routing.yml.

how is this possible in Symfony2?,that is if i have to access more than one action in a twig without specifying in routing.this is useful while using ajax.

Thanks in advance

If I understand your question correctly, you're asking how you can generate a url by passing a module name and action name, instead of a route name. Is that right?

I don't think this is possible in Symfony2. If you take a look at the generate method in Symfony\Component\Routing\Generator\UrlGenerator you'll see that it expects a route's name as the first parameter. Also, Symfony2 doesn't natively support the generic routes that symfony 1 does (shown below for reference).

default_index:
  url:   /:module
  param: { action: index }

default:
  url:   /:module/:action/*

Without these generic routes, you can't simply access /myModule/myAction without actually defining a route for it. And don't forget that Symfony2 now uses bundles, which would complicate this further.

So for whatever actions you want to access, you'll need to write routes for them.

In order to actually generate the URLs...
- From a controller: $this->generateUrl($routeName);
- From a PHP template: $view['router']->generate($routeName);
- From a Twig template: {{ path('_routeName') }} or {{ url('_routeName') }} for an absolute URL

jQuery 1.7 selector error

6 votes

this is my very first question.

I'm working on a fully Ajax system with jQuery, and it works fine with 1.6.2. When I tried to upgrade it to 1.7, this piece of code stopped working properly:

$("a[class!='']").live("click",function(e){
    e.preventDefault();
});

In 1.6.2, it prevents all hyperlink tags from working as a link if they have a class, but in 1.7 it stopped ALL links from working as real links, even those without classes.

Fiddle: http://jsfiddle.net/hBehg/

Use $('a[class]'), this will select all elements which have the class attribute. As I said in my comment, checking for an empty value might not work if the element does not even have a class attribute.

Update: As pointed out by @Sidnicious, the documentation describes that this selector will also select those elements which do not have that attribute. If it didn't in 1.6, then it actually must have been a bug in that version, or they changed the description without mentioning it.

Of course, if you indeed have an empty class attribute, i.e. <a class="">, this will not work.

DEMO

Update 2: As @lonesomeday mentions in his comment, $('a[class][class!=""]') does work as you intended with $(a[class!=""]).

As others said, you can change to on in jQuery 1.7, which unifies the event handling methods, but it won't solve your particular problem.

Firefox + jQuery on OS X doesn't show errors thrown in AJAX handlers?

6 votes

When an error occurs in a jQuery AJAX handler on Firefox + jQuery + OS X the error seems to be silently ignored.

Example code: http://jsfiddle.net/bGuX9/

Chrome correctly reports both errors in the JavaScript console:

error in Chrome

But Firebug in Firefox only reports one error, even though two have been thrown (as evidenced by the “Throwing error: in ajax”):

error in Firefox

The above is Firefox 8 on OS X 10.6, but I've noticed the issue as far back as Firefox 3.5. Firefox on Windows (tested with 8) doesn't seem to be affected.

What's up with this? Is this a known issue?

A couple notes:

  • I don't believe this is an issue with Firebug, as the error doesn't appear in Firefox's error console either.
  • I know that I can use a try/catch block in my event handler and catch the error there, but that doesn't help me debug arbitrary code.

After much searching, it looks like this issue is caused by the Adblock Plus extension, as it only occurs when the extension is enabled.

A bug has been filed on the Adblock Plus forum: https://adblockplus.org/forum/viewtopic.php?f=11&t=8761

How does GitHub to avoid lag / blink on page loading?

6 votes

When I navigate into my GitHub dashboard, It look like the page is not reloaded, but only the content which changed.

So my first thought was that it is a classic ajax trick, but when I change the content of the page (change header title via the google debugger for example) that is not supposed to be reloaded (as in the ajax hypothesis), and I click to a link, my change is reset, so this part of the page is reloaded as well, BUT it doesn't blink at all, so how do they do it?

https://github.com/defunkt/jquery-pjax will give you all of the magic, as a jQuery plugin

How to do a ajax request for login

6 votes

I have this in my PHP code, and it currently does the login request in the same login.php page but now i want to do it with Ajax. Basically I have this in the login.php

       echo '<form method="post" ><div id="login" class="login">
        <label for="login">User Name</label>
        <input type="text" name="logInUsername" />
        <label for="Password">Password</label>
        <input type="password" name="logInPassword" />
        <input type="submit" value="Submit"  name="submitlogin" class="button" />
        </div>';

I would like to still use this but have a login_request.php or something where i can send the username and password validated and then change the <div id=login> to say you are logged in!</div> I can do it the conventional way, with the form post .. but now I would like to try it with Ajax.

Any help will be much appreciated.

Regards

What have you tried so far? This is how I would start:

This should get you started:

HTML:

<form id="loginForm" ><div id="login" class="login">
    <label for="login">User Name</label>
    <input type="text" name="logInUsername" />
    <label for="Password">Password</label>
    <input type="password" name="logInPassword" />
    <input type="button" value="Submit"  id="submitlogin" class="button" />
    </div>
</form>

jQuery:

$("#submitlogin").click(function() {

  inputs =   //grab then inputs of your form #loginform
$.ajax ({
       url: "urltoyourloginphp.php",
       data: inputs,
       success: function() {
        $("#login").html("You are now logged in!");
}
  });
}

What is the proper way to structure/organize javascript for a large application?

6 votes

Let's say you are building a large application, and you expect to have tons of javascript on the site. Even if you separated the javascript into 1 file per page where javascript is used, you'd still have about 100 javascript files.

What is the best way to keep the file system organized, include these files on the page, and keep the code structure itself organized as well? All the while, having the option to keep things minified for production is important too.

Personally I prefer the module pattern for structuring the code, and I think this article gives a great introduction: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

It keeps my global scope clean, enables namespacing and provides a nice way to seperate public and private methods and fields.

I'd structure the code in separate files, and seek to keep coupling low and cohesion high. Although multiple files are bad for client performance (you should minimize the number of requests), you'll easily get the best from both worlds using a compression utility.

I've some experience with YUI Compressor (for which there is a Maven plugin: http://alchim.sourceforge.net/yuicompressor-maven-plugin/compress-mojo.html - I haven't used this myself). If you need to order the javascript files in a certain way (also applies for CSS), you could make a shell script, concatenating the files in a given order in advance (Tip: YUI Compressor defaults to STDIN).

Besides, either way you decide to minify your files will probably do just fine. Your focus should instead be on how you structure your code, so that it performs well on the client (should be highest priority in order to satisfy a good UX), and is maintainable in a way that works for you.

You mention namespaces, which is a good idea, but I'd be careful to adopt too many concepts from the traditional object oriented domain, and instead learn to utilize many of the excellent features of the javascript language :)

Javascript hashing in AJAX login calls, more security?

5 votes

From a lot of posts I've seen on the site, logins performed by AJAX or traditional forms are just as secure as one another. (re: Login/session cookies, Ajax and security Ajax login and javascript cookies, is this secure?)

My question(s) is/are:

  1. If I hash the user's password (via client-side/javascript hash libraries) before I send it to the server, do I increase security from people easedropping?

  2. If I put a form token (one random based, another time based), does that cover CSRF attacks?

  3. Would I have all my bases covered after all this? Would this form be secure?

Actually this could be a major security problem. The reason why passwords are hashed is a means of planning on failure. An attacker might gain access to the data store (sql injection) and then obtain the hash. If you are just logging in with a hash, then the attacker doesn't have to crack the recovered hash in order to gain access to the application.

Replay attacks are also a problem. If I sniff the hash during authentication, whats stopping me from just replaying that request to authenticate?

Protocols that use message digest functions for authentication provide the client with a nonce, which is used as a one time salt. Microsoft's SMB NTLM authentication is a good example, but it has had a lot of problems.

USE SSL, and not just for login. OWASP A9 states that the session id must never be leaked over an insecure channel. After all who cares about the password if you just spill the real authentication credentials a few milliseconds later.

Most people don't implement CSRF protection for login. After all the attacker would have to know the password in the first place, so "session riding" is a moot point.

My function won't run?

5 votes

I'm getting tired of firebug telling my vars aren't defined...

I have a button: next. When the button is clicked, I want it to load a php page into a div, assigning the php page the variable representing the next page.

To do this, I have a variable crntpage that stores the value of the current page. In order to calculate what the var for the next page must be I have a function called next which calculates the value and returns it.

Let's assume that we are on page 5:

javascript

$(document).ready(function() {

$.ajax({
    url: 'pagination.php',
    type: 'POST',
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    async: true,
    cache: false,
    success: function (pages) {
                last = pages['last'];
                crntpage = 1;

                function nxt(b) {
                    if (b == last) {
                        next  = last;
                    } else {
                        next = b + 1;
                    }
                    return next;
                }

                $('#next').live('click', function() {
                    crntpage(next);
                    $('#content').load('getposts.php?pagenum=' + nxt(crntpage));
                    return false;
                });
    }
});
});

html

<div id="previous"> 
        <a href=''> <-Previous</a>
</div>

I keep getting an error saying that next isn't defined. My guess is because my nxt function is not receiving the value of last. What am I doing wrong?

What you are trying to do with the nxt function can be accomplished more idiomatically with Math.min():

$('#next').live('click', function() {
    crntpage = Math.min(crntpage + 1, last);
    $('#content').load('getposts.php?pagenum=' + crntpage);
    return false;
});

You should also prefix variable declarations with the var keyword, so as not to pollute the global namespace.

Here's the revised code together:

$(function() {

    var currentPage = 1;
    var last = 1;

    $('#next').live('click', function() {
        currentPage = Math.min(currentPage + 1, last);
        $('#content').load('getposts.php?pagenum=' + currentPage);
        return false;
    });

    $.ajax({
        url: 'pagination.php',
        type: 'POST',
        contentType: "application/json; charset=utf-8",
        dataType: "json",    
        cache: false,
        success: function (pages) {
            last = pages['last'];
        }
    });

});

Javascript (with Ajax) from PHP and Output Buffering

4 votes

Thanks already to advice from Stackoverflow subscribers I now have a working JSON formatted file from my PHP scripts.

The next step is to have a Javascript script to retrieve this data for sorting, filtering and displaying.

I have a working Ajax script that tests ok for pulling back data, but I need to personalise this to the individual.

Within PHP I have a Session variable called MID (Member ID).

I am trying to use PHP to build the Javascript with the unique URL with the MID as a variable.

The following all seem to work except for replacing the midValue variable in the Javascript text with the MID variable in the outer PHP script.

The code so far looks like this ...



    // This is a PHP file
    // Setup PHP Output Buffering to change the MID value
    session_start();
    $MID = $_SESSION['MID'];

    function callback($buffer)
    {
      return (str_replace("midValue", $MID, $buffer));
    }

    ob_start("callback");

/*

Some bits I can't show as I haven't figured out the correct Stackoverflow tags (!) ...

 - Add the usual HTML tags such as `HTML, HEAD, TITLE, BODY, SCRIPT` etc
 - Include a DIV with an ID of **json**, this will be replaced by the JSON output it
   self.
 - Enclose the params variable with the `CDATA` tags to maintain the ampersand.

*/
    params = "url=server.com/content.php?action=json&MID=" + midValue

    request = new ajaxRequest()
    request.open("POST", "getcontent.php", true)
    request.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
    request.setRequestHeader("Content-length", params.length)
    request.setRequestHeader("Connection", "close")

    request.onreadystatechange = function()
    {
        if (this.readyState == 4)
        {
            if(this.status == 200)
            {
                if(this.responseText != null)
                {
                    document.getElementById('json').innerHTML = this.responseText
                }
                else alert("Ajax Error: No data recieved")
            }
            else alert("Ajax Error: " + this.statusText)
        }
    }

    request.send(params)

    function ajaxRequest()
    {
        try
        {
            var request = new XMLHttpRequest()
        }
        catch(e1)
        {
            try
            {
                request = new ActiveXObject("Msxml2.XMLHTTP")
            }
            catch(e2)
            {
                try
                {
                    request = new ActiveXObject("Microsoft.XMLHTTP")
                }
            catch(e3)
                {
                    request = false
                }
            }
    }
    return request
   }

/*
Add the closing `SCRIPT, BODY and HTML` tags here.
*/

    ob_end_flush();

And the getcontent.php file looks like this ...



       if(isset($_POST['url'])) {
            echo file_get_contents("http://" . SanitizeString($_POST['url']));
       }

       function SanitizeString($var) {
        $var = strip_tags($var);
        $var = htmlentities($var);
        return stripslashes($var);
       }

Any assistance gratefully received.

Thanks, Pete.

I think something simpler like this should work fine for you.

<?php

session_start();
$MID = $_SESSION['MID'];
?>

params = "url=server.com/content.php?action=json&MID=<?php echo $MID ?>"

request = new ajaxRequest()
request.open("POST", "getcontent.php", true)
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
request.setRequestHeader("Content-length", params.length)
request.setRequestHeader("Connection", "close")

... // rest of javascript

<?php include 'footer.php'; // include footer code here ?>

With this method, you are just outputting the javascript and html outside of PHP so you don't need it in tags. Then you can just echo variables or include your header and footer where required.

Get environment inside controller

4 votes

I have a situation in one of my controllers that should only be accessed via AJAX, I have the following code.

if (!$request->isXmlHttpRequest()) {
    $response = new Response();
    $response->setContent('AJAX requests only!');
    return $response;
}

When I am testing this gives me an issue because the request hasn't actually been made via AJAX. This then breaks my tests every time. How should I go about working around this?

My Ideas:

  1. I have tried to set a server header but have had absolutely no success.
  2. Check if I am in the test environment in the controller and don't do the check if it is. I know this is dirty, but it would work. :-/ The problem was that I couldn't figure out how to discover what environment I am in.

Anyone else have any other ideas or tips that I am missing to get one of the above to work?

Looking at the code for isXmlHttpRequest in class Request and method getHeaders in class ServerBag, the piece of code below should do the trick:

$client->request(
    'GET',
    '/path/to/test',
    array(),
    array(),
    array(
        'HTTP_X-Requested-With' => 'XMLHttpRequest',
    )
);

I did not test it personally but I think it should works. The line of code below in Request is used to check if the http request is a XmlHttpRequest.

return 'XMLHttpRequest' == $this->headers->get('X-Requested-With');

In the code, $this->headers is set using:

$this->headers = new HeaderBag($this->server->getHeaders());

The method getHeaders creates an array of headers. Each server variable starting with HTTP_, plus some special server variables like CONTENT_TYPE, are put in this array.

Hope this helps.

Regards,
Matt

How to call function on parent page from iframe using jQuery?

4 votes

I have an upload form that posts to a hidden iframe. I am attempting to call a function on the parent page from the iframe, but am getting the error "top.stopUpload is not a function".

What is the correct way to do this?

PARENT PAGE:

$(document).ready(function() {

    $('#document_upload').submit( function() {

        $('#upload_progress').show();

     });

    function stopUpload(success){

        if (success == 1){
            $('#result', window.parent.document).html(
            '<span class="msg">The file was uploaded successfully!<\/span>');
        }

        else {
            $('#result', window.parent.document).html(
            '<span class="emsg">There was an error during file upload!<\/span>');
        }

        $('#upload_progress').hide();

        return true;

    }

})

IFRAME:

$(document).ready(function() {

   top.stopUpload(<?php echo $result; ?>);

}

Your stopUpload() function is scoped to the anonymous function you pass to $(document).ready().

You will need to ensure its scope is visible to the iframe. One way to do that would be to assign the function to window, the global object in a browser.

Another method would be to create the function in the global code, outside of that anonymous function.