Author Archive

Same origin policy problem with AJAX/AJAH

In my case the same origin policy problem came up because I needed to make our website content available on a foreign website by using the Reverse Proxy technique. Which means that another website grabs our content and includes it into theirs. So for the users it looks like the content comes native from the foreign website.

The thing which made it a problem was, that we use a lot of “AJAX/AJAH” requests to process  form data etc.

Now if our native domain is native.com, the partner domain is partner.com (which includes our content) but the AJAX resource is still native.com the access would be forbidden by the same origin policy.

For instance if you observe such a XHR with Firebug, you’ll get a 200 Status, but the response body is empty.

If you google for a solution for this problem you’ll stumble across the buzz word Cross-origin resource sharing (CORS). But this technique just works for recent browsers like IE9+ etc.

Another way to solve the problem is the usage of the script-tag which allows cross-origin access and works with almost every common browser.

So lets work out the solution – by the way I use the jQuery framework -

Instead of catching the AJAX data with

    $.get(ajaxurl, function(data) {
      $('#resultsContainer').html(data);
    });

you need to get the data by adding a new script tag with the ajaxurl:
(I avoid to explain the whole solution path, it would go beyond the scope)

    if($('#ajaxScript').length!=0)
    {
      $('#ajaxScript').remove();
    }

    // Build temporary script tag to get AJAX results
    var scriptUrl             =  ajaxurl+'&useAsJsFunction=1';
    var script                = document.createElement( 'script' );
    script.type               = 'text/javascript';
    script.src                = scriptUrl;
    script.id                 = 'ajaxScript';

    if (script.addEventListener) // for normal browsers
    {
      script.addEventListener('load', function(){
        setAjaxData();
      }, false);
    }
    else // for old IEs
    {
      script.onreadystatechange = function(){
        if (script.readyState in {loaded: 1, complete: 1}) {
          script.onreadystatechange = null;
          setAjaxData();
        }
      };
    }

    document.body.appendChild(script);
    $(script).remove();

    function setAjaxData()
    {
      var ajaxData = getAjaxDataString();
      $('#resultsContainer').html(ajaxData);

      // Clean up the objects:
      $(ajaxData).remove();
    }

Explaination:

1. I enhanced the old ajaxurl with the parameter “&useAsJsFunction=1″. So the script behind the URL will build a javascript function body around the HTML data:

<?php if($useAsJsFunction): ?>
  function getAjaxDataString()
  {
    var data = '<?php echo str_replace(array("\r\n", "\r", "\n"), "", trim($content)); ?>';
    return data;
  }

<?php else: ?>

<?php echo $content; ?>

<?php endif; ?>

2. I set the ID attribute to the script tag for an easy later access to remove it from the DOM after I get the data. Because or otherwise every AJAX call will enhance a new script tag to the DOM.

3. The browser needs a while to load the foreign script containing the getAjaxDataString()-function which returns the ajax data. So I tried a lot of different ways with the setTimeout function etc. But I found the best solution to this async problem on phpied.com (thx a lot for your post). Instead of setting up an arbitary timeout it’s better to use the event handler when the script is loaded (onreadystatechange respectively onload).

4. getAjaxDataString(): I needed to remove the linebreaks etc. from the HTML string to avoid JS syntax errors. The HTML string inside of $content has no additional escaping stuff. But this would be different if you use JS code inside the returning HTML string!

5. document.body.appendChild(script) appends the script tag to the DOM. There are different ways to add it, but adding it to the body was the most readable way for later code reviews. First I used the head-tag as parent, but this caused problems with IE8 and older browsers.

6. $(script).remove() and $(ajaxdata).remove() are just to release the memory of these sometimes big objects, because they’re created more the once during a session.

 

Your’re welcome to post comments or improvements to my explanations.

 

Links:

Edit:

  • I don’t know why, but it’s funny that this solution seems to be faster than the jQuery XHR.
  • It does not work with Opera.

jQuery: Problem with hidden selectbox

I use the jQuery SelectBox Plugin for a select box in a hidden DIV container. The problem was that after removing the hidden CSS class from the container, the jQuery SelectBox was empty. I thought that maybe it is in correlation with this statement from A Beautiful Site:

Since the original controls aren’t destroyed (they’re hidden), you can easily integrate this plugin into just about any existing form.

so the only way to get the SelectBox filled correctly was to first destroy  and then reinitialize it (see the code snippet below).

<style>

.hidden {
  display: none;
}

</style>

<script>
$(document).ready(function() {

  $('#show').bind("click", function(){

     $('#container').removeClass('hidden');
     $("#container select").selectBox('destroy');
     $("#container select").selectBox();

  });

  $("select").selectBox();

});
</script>

<a id="show" href="#">show</a>

<div id="container" class="hidden">
  <select>...</select>
</div>

Symfony 1.4: symfony generator Invalid column name ‘id’

It seems that the symfony generator needs a primary key. If there’s no PK defined the generator throws the following exception:

symfony generator Invalid column name ‘id’

In some blog post they solved the problem by adding a primary key to the concerning table. But in my case the DB isn’t under my control, so I found out that it is enough to set the primary key only in the schema.

For instance:

my_table:
  connection: doctrine
  tableName: MyTable
  columns:
    id:
      type: int(11)
      primary: true  # <-- SET TO true

Windows Azure: Compute Emulator: Can’t locate service model

Just to share, if you get this error messag:

The compute emulator had a error: Can’t locate service model..

for instance when starting “package create …“, the problem could be a too deep project folder structure. In my case caused by the file cache directory of my application. After clearing this directory everything was ok.


Windows Azure: Custom PHP installation

I write this article because of an odyssey of bug tracing concerning my PHP application hosted in the Windows Azure cloud.

Before the Windows Azure SDK 1.6 the configuration of PHP with Fast CGI was done in the Web.config. Here you could define the exact path of your custom PHP.

Now with the SDK 1.6 and the different folder structure defined by the scaffolder, the integration of PHP has changed. The new way is to install PHP automatically by the predefined startup scripts. So you don’t need to put the whole PHP stuff into your package. You just add your php.ini modifications and maybe your special PHP extension DLLs.

Now, when you deploy your package the startup scripts will add some environment variables,  install PHP53, SQLDriverPHP53IIS and PHPManager.

That’s all quite cool, but last week my live application crashed (WORST CASE!) without any modifications by my side. I could not find the problem. A few days ago I recognized that on the compute instances runs a different PHP version than on my local dev environment. I could not figure out how this could happen. But since I know that the startup script uses webpicmdline (Web Plattform Installer for Commandline) to install the PHP stuff (s.o.) it’s clear to me. The WebPI always takes the newest PHP version for installation, and it’s not possible to set up a specific version number. In my case in need PHP 5.3.8 but WebPI installs PHP 5.3.9 which crashes my application with an ugly PHP53_via_FastCGI Error Code 0xc0000005.

Ok, how can I tell Azure to take my PHP version. The only way is to again put the whole PHP folder into the deployment package as explained in this tutorial.

I for my use case I needed to do it a little bit different:

  • I put the PHP folder into MyProject\WebRole\bin\PHP\v5.3\php-cgi.exe
  • The extensions are in MyProject\WebRole\bin\PHP\v5.3\ext\
  • In configureIIS.cmd I changed SET PHP_FULL_PATH=%~dp0php\php-cgi.exe to SET PHP_FULL_PATH=%~dp0PHP\v5.3\php-cgi.exe
  • To add the environment variables I leave add-environment-variables.cmd as it was
  • To set user permission I leave monitor-environment.cmd as it was

These changes bring some small losings (with which I can live):

  • SQLDriverPHP53IIS needs to be installed manually (ext\php_sqlsrv_53_nts_vc9.dll [2]).
  • No IIS PHPManager (Maybe it’s possible to install it by modifing the install-php.cmd).

The startup script part in my ServiceDefinition.csdef now looks like:

    <Startup>
      <Task commandLine="add-environment-variables.cmd" executionContext="elevated" taskType="simple" />
      <Task commandLine="installCustomPHP.cmd" executionContext="elevated" taskType="simple">
        <Environment>
          <Variable name="EMULATED">
            <RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />
          </Variable>
        </Environment>
      </Task>
      <Task commandLine="monitor-environment.cmd" executionContext="elevated" taskType="background" />
    </Startup>

I renamed the configureIIS.cmd from the tutorial to installCustomPHP.cmd.

One thing: It very strange to make the experience as Azure PHP developer that there are sometime changes within the Azure Plattform which are crashing my live application. And I have no chance to get warned/informed early enough to fix the problems before my customers get a blank page.

Corrections, tips and hints are welcome :)

Links:


Copyright © 2007-2012 iTopia. All rights reserved.
Jarrah theme by Templates Next | Powered by WordPress