Question

I have built a Facebook App that requires some image upload functionality and to implement it I'm using Fine Uploader.

The Facebook App itself is built with WordPress and everything is working fine. Eventually the WordPress website (which is the App) is going to live on Facebook in an iframe and it's here that things are getting interesting.

When I test the app on my local machine it works (all browsers). When I test the app outside the iframe on my staging environment it also works (all browser). However, when I test the app in a test page on Facebook (iframe) the image upload fails, only in IE.

For reference I will show my server and client code:

public static function upload_receiver()
{
    $uploader = new qqFileUploader();
    $uploader->allowedExtensions = array("jpg", "jpeg");
    $uploader->sizeLimit = 2024 * 1024;

    $wp_upload_dir = wp_upload_dir();
    $wp_upload_url = $wp_upload_dir['baseurl'];
    $wp_upload_base = $wp_upload_dir['basedir'];

    $upload_dir = $wp_upload_base;
    $upload_filename = md5(mt_rand())/*.'_'.$uploader->getName()*/.".jpg";

    $result = $uploader->handleUpload( $upload_dir, $upload_filename );

    // Create the WordPress image thumbs.
    $img_target = "{$upload_dir}/{$upload_filename}";

    $wp_filetype = wp_check_filetype( $img_target );

    $attachment_data = array(
        'post_mime_type' => $wp_filetype['type'], 
        'guid' => $img_target,
        'post_title' => preg_replace('/\.[^.]+$/', '', $upload_filename ),
        'post_name' => preg_replace('/\.[^.]+$/', '', $upload_filename ),
        'post_content' => '',
        'post_status' => 'inherit',
    );

    $attachment_id = wp_insert_attachment( $attachment_data, $img_target );

    $meta = wp_generate_attachment_metadata($attachment_id, $img_target);

    wp_update_attachment_metadata($attachment_id, $meta);   

    $result['attachmentId'] = $attachment_id;
    $result['imageUrl'] = htmlspecialchars( get_image_url_from_attachment_id($attachment_id, "thumb-small") );

    header("Content-Type: text/plain");
    echo json_encode( $result );

    die();
}

And the client:

var el = $('#upload');
var el_img = el.find('span');

el.fineUploader( {
    uploaderType: 'basic',
    button: el,
    multiple: false,
    request: {
        endpoint: '<?php echo site_url("/wp-admin/admin-ajax.php") ?>',
        params: {
            action: 'upload_receiver'           
        }
    },
    validation: {
        allowedExtensions: ['jpeg', 'jpg']
    },
    debug: false
} ).on('upload', function(event, id, fileName, response) {
    $('.loader').show();
    $('.upload_button_container').hide();

} ).on('complete', function(event, id, fileName, response) {

    // ONLY IN IE "RESPONSE.SUCCESS" IS FALSE IN AN FB IFRAME. ALL OTHER
    // TIMES "RESPONSE.SUCCESS" IS TRUE AND ALL PROPERTIES CREATED ON THE
    // SERVER EXIST.

    $('.loader').hide();
    $('.upload_button_container').show();

    if( response.error )
    {
        alert( response.error );
        return;
    }

    // Display image coming in from the result.
    $(".img_upload_container img").attr('src', response.imageUrl).show();

    // Store the WordPress attachment Id for form submission.
    $("form input[name=bc_attachment_id]").val( response.attachmentId );
});

I have been banging my head on this for the past few hours and I've run out of ideas of might be causing this issue.

EDIT:

IE9 console output:

LOG: [FineUploader] Processing 1 files or inputs... 
LOG: [FineUploader] Sending upload request for 0 
SEC7111: HTTPS security is compromised by res://ieframe.dll/forbidframing.htm 
SEC7111: HTTPS security is compromised by res://ieframe.dll/ErrorPageTemplate.css 
SEC7111: HTTPS security is compromised by res://ieframe.dll/errorPageStrings.js 
SEC7111: HTTPS security is compromised by res://ieframe.dll/httpErrorPagesScripts.js 
SEC7111: HTTPS security is compromised by res://ieframe.dll/red_x.png 
SEC7111: HTTPS security is compromised by res://ieframe.dll/bullet.png 
SEC7111: HTTPS security is compromised by res://ieframe.dll/background_gradient.jpg 
LOG: [FineUploader] Received response for 0 
[FineUploader] Error when attempting to access iframe during handling of upload response (Error: Access is denied.
) 
LOG: [FineUploader] iframe loaded 
[FineUploader] Error when attempting to parse form upload response (Error: Access is denied.
) 
Was it helpful?

Solution

As I suspected, the problem is that the domain of the parent window does not match the domain of the iframe containing the response. This is a security violation, and there is no simple way to access the contents of this iframe since it is on a different domain. This sort of access is prohibited by the browser. It is a bit tricky to get around this, but Fine Uploader provides a way.

You will need enable the CORS feature in Fine Uploader. This is probably your best option, and this should solve your problem. Fine Uploader recently added support for cross-domain requests (version 3.3). This is particularly useful in IE, where iframes are involved. Essentially, you will configure your response to import a javascript file that will post a message to the parent window containing your response. This is how Fine Uploader overcomes the cross-domain issue. I wrote up a detailed blog post on CORS support in Fine Uploader, and how you can enable it and properly handle cross-domain requests sent by Fine Uploader in your server side code.

If you read the post and follow the server-side instructions, it seems like you should be fine.

Note that this only seems to be an issue you need to overcome in IE9 and older, in your case. Here's a high-level summary of what you need to do:

  1. Turn on CORS support in Fine Uploader (client-side).
  2. Server-side: identify non-XHR upload requests by looking at the X-Requested-With header on the request.
  3. If the request was not sent via XHR, return a response, with a content-type of "text/html", that starts with a <script> tag that imports the "iframe.xss.response.js" file from a known location (anywhere). After the script tag in your response, include the normal valid JSON portion of the response.

Hope this helps.

OTHER TIPS

Just to add on to @Ray's answer in a different scenario whereby the iframe is of the same domain, but the same SEC7111: HTTPS security is compromised by res://ieframe.dll is still received in https environment:

For Apache, HTTP Server

Add/Change following line in Apache Web Server’s httpd.conf file

Header always append X-Frame-Options SAMEORIGIN

Make sure it is not set to DENY. Restart web server

Do also check the response header to see the above change being reflected

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top