Safari, AJAX and "broken" encodings

Some lessons are learned the hard way.
I was doing another AJAX based system today, and faced a problem where the Ajax.Updater updated text was shown correctly in every single browser except for Safari.
Like I wrote in one of my previous posts, one should check if the output to browser from a script is sent in UTF-8, because this is the encoding AJAX supports. So, in my case with Japanese-language web-sites, I have ordinary pages encodings set to ShiftJIS. So, when I output text which is supposed to be used to replace web-page contents using Prorotype's Ajax.Update call, I convert it from ShiftJIS to UTF-8 before outputting as the result of AJAX call.

And the code might look like that:

ob_start(); //starting output buffer
print_eventsList("month", $_REQUEST["y"], $_REQUEST["m"]); //outputting everything to output buffer
print "some additional output functions might be here";
$out = ob_get_clean(); //getting results of the output buffer
print mb_convert_encoding($out, "UTF-8", "SJIS"); //converting output from server's default encoding to UTF-8 and outputting it as the result of AJAX call

So, the problem was that the code above worked in Firefox, Camino, IE 6.0 on Windows, but was rendered incorrectly on Safari. The encoding was kind of "broken". Tried lots of thing before finally found the solution (and it works on every browser!). It looks like all browsers except for Safari have the XMLHTTPRequest encoding set to UTF-8 by default. And Safari.. I don't know if it has any defaults at all. So I decided to set the encoding of the AJAX output result in the header of the output - AND IT WORKED!

Just one line of code has to be added:

header("Content-type:text/html; charset=utf-8");

and the final code:

ob_start();
print_eventsList("month", $_REQUEST["y"], $_REQUEST["m"]);
print "some additional output functions might be here";
$out = ob_get_clean();
header("Content-type:text/html; charset=utf-8");
print mb_convert_encoding($out, "UTF-8", "SJIS");

So.. good luck in making AJAX calls and happy coding ;)


UPDATE!

Actually, all you need is to send header with your server's default encoding. So if all pages on your server are generated in ShiftJIS encoding, just add the following header

header("Content-type:text/html; charset=shift_jis");

13 Responses to “Safari, AJAX and "broken" encodings”

  1. simon Says:

    great. thanks.

    still i got a problem: all my ajax-loaded pages are displayed correctly by Safari now. But sending them doesn't work: One page contains a form which i sent to the server by XMLHTTPRequest: the values of that form though do not seem to arrive in UTF-8. It works with all known Browsers but with Safari. Do you know a workaround?

  2. mike Says:

    i didn't try to send much stuff using AJAX in Safari, but my first guess would be to check what kind of data Safari sends to the script. It could be that it sends data in page's default encoding which might not be UTF-8 for example. If you have a link to a test page it would be interesting to look at it and may be I can help.
    One more thing - it looks like Safari conforms to standards to a better degree than other browsers, so it might be that the code misses some required part which other browsers just forgive. But.. I'm afraid I can't say more that that right now. May be if I have time I'll try the thing myself and see how it works in Safari.

  3. Nick Says:

    I think I have a simular problem. Within Safari everything looks fine as all dashes are dashes and all pound signs are pound sign. Though within IE dashes and pound signs are shown as hashes. From what I have read above this is because of how the data is encoded when being passed too and from AJAX coding. Can anyone confirm that this could be the case. Thanks.

  4. Nick Says:

    Sorry I meant "?" not hashes.

  5. Paul Girard Says:

    My turn to add an other trick about SAFARI/HTTPREQUEST and charset.

    I learned from you that I need to specify the charset by rewriting the header information. This does the trick until I needed to make synchronous requests.

    It appears that using httprequest with the third argument as false (i.e. synchronously) makes UTF-8 unreadable by SAFARI…

    I can't understand why ?
    This is driving me made…

    Paul

  6. Rickyok Says:

    Wuaaaaaaa. thank youuu. I lovee youuu mikee!! I fixing the AJAX with shift-jis bug 3 hours. And the only mistake i made was i type shift-JIS in the content-type. Ohhhh nooo T_T it should be shift_JIS

    ThAnK Y0U!

  7. mike Says:

    you're welcome Rickyok :)

  8. Rich Harris Says:

    Thank you! Thank you! Thank you! Thank you! Thank you! Thank you! A million times over!

  9. eu Says:

    i am using asp .. i m not sure whether i using the write way to set the charset onot and it doesn't work in Safari .. not sure where is the mistake ..

  10. Doug Lerner Says:

    This is driving me crazy too. I'm not using ASP either. I seem to be sending the correct content-type from my server though:

    addResponseHttp( "Content-Type:text/html; charset=shift_jis" )'

    but the Japanese that comes back from my AJAX/Prototype calls seem garbled.

    doug

  11. Veselin Kulov Says:

    Finally solved my problem. Turned out that Safari is not switching to UTF-8 on a text/json response. I have charset set to utf-8 inside the html and in all http response headers (both for html and the json). And now my unicode characters are not displayed properly in Safari. What the heck, it even works in IE6 but not in Safari :)

    Turned out that I'm missing the charset attribite in the tag. I'm using ScriptSrcIO as a transport mechanism.

  12. Christophe Sautot Says:

    After having pretty much the same problem as you, with a Japanese AJAX call, I Google'd "safari ajax utf8" and your post popped up as the first result - fabulous!! Thanks for your write-up.

  13. Joran Says:

    I had the same problem.

    I had "AddDefaultCharset UTF-8" in my .htaccess file to automatically add a UTF charset header to all server responses.

    Safari was working fine with the data when shown using a straightforward PHP/MySQL page. When I showed it using AJAX, the encoding cracked open in only Safari.

    It seems Apache's charset header didn't count when it came to Safari. Setting it manually in the back-end PHP script for my AJAX request solved the problem. Just like you said.

    Thank you!

Leave a Reply