I want to create a script (javascript file. JS) that I can put from my domain on every website. The script has to read the text from the website and send it to the server. The server is on another domain than the website from which it reads the text, that is why I use JSONP. The read text can be charsed in different ways (different languages – websites from all over the world) and they can be very long that’s why, before sending them I code them by base64, divide them into data packets and send them separately using GET (JSONP).
Without the definition of getJson() function, the code is:
var sBase64Code = base64_encode( document.getElementById('idText').innerHTML );
// we devide sBase64Code into data packets,
// and changing it to array aBase64Code – I skip this algorythm
// and then I send packets to the server in loops
for(i in aBase64Code) {
getJson(['idx='+i, 'code='+aBase64Code[i]], hFunCallback);
}
However, after sending the code to the server, joining the packets and decoding data by base64_decode() it turns out that chars different from English ones are lost.
mb_convert_encoding(base64_decode($b64), mb_detect_encoding(base64_decode($b64))) doesn’t work.
JavaScript base64_encode() function is:
function base64_encode(data) {
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc = "", tmp_arr = [];
if(!data) return data;
do {
o1 = data.charCodeAt(i++);
o2 = data.charCodeAt(i++);
o3 = data.charCodeAt(i++);
bits = o1 << 16 | o2 << 8 | o3;
h1 = bits >> 18 & 0x3f;
h2 = bits >> 12 & 0x3f;
h3 = bits >> 6 & 0x3f;
h4 = bits & 0x3f;
tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
} while (i < data.length);
enc = tmp_arr.join('');
var r = data.length % 3;
return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
};
Example of sending data:
Base64 from example: WndpbmkZdGEgbmkHIHRvIGtCGWJlay4=
Related
I want to list the latitude and longitude of itinerary. It could be all points or it could be all points in 1-2 kilometers.
What I'm trying to do is: user selected A as the starting point and B as the ending point. I want to show some places near the road between A and B on the map. But I need a positions for this.
As an example, a JavaScript code is shared here and It is said that this can be done with DirectionsResult Object.
var request = {
origin: start_point,
destination: end_point,
travelMode: google.maps.TravelMode.DRIVING
};
var directionsService = new google.maps.DirectionsService();
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var path = (response.routes[0].overview_path);
}
});
But I'm trying to do this with php and I have to do this with php.
I read google map api. I've also read the yandex map api, but this seems to be done only with javascript.
Does anyone know a way to do this with php?
From comments I understand the question is to find (using PHP) the intermediate lat,lng pairs that can be extracted from the polyline points in a google directions query.
This is a bit unusual because people normally use the polyline points for map drawing in the browser, and so the JavaScript libraries are well equipped for this task. However, not so in PHP.
The points data appears in the JSON result object as string of ascii characters, sometimes quite long and always 'unreadable'. Into this string is encoded a list of intermediate lat lng pairs between the start and end of each leg. The coding method is presented at the google site https://developers.google.com/maps/documentation/utilities/polylinealgorithm and the algorithm below is just a reversal of that and is commented accordingly.
The example shows a directions find between 2 points, on crescent shaped streets, in Perth, Australia. The start-end points were chosen to encourage multiple intermediate points as would be needed to draw the route. Substitute your own search as needed.
Note that the JSON also provides these fields also at the end of each results object.
"overview_polyline" : {
"points" : "~n{aEmbwaU_B#cCBk#Lo#d#UVOb#Mh#Ab####BBF#DGNABD`#Fh#Pb#VZn#b#d#J"
},
This is much less detailed and less accurate (if you draw will probably depart from actual road lines on map), but can also be decoded in the same way.
The best intermediate points are however, by iterating through the steps using:
"polyline" : {
"points" : "~n{aEmbwaUg##w#?{A?g#BUBUHSJ[XUVOb#Mh#Ab#"
},
Finally, the original source for the algorithm can be found here http://unitstep.net/blog/2008/08/02/decoding-google-maps-encoded-polylines-using-php/. So thanks to Peter Chng for this work back in 2008! Peter also acknowledges Mark MClure who did the original coding in JavaScript. I hacked about with and added more comments - to make more aligned with the google recipe, but no more.
I have also just realised there is this link https://github.com/emcconville/google-map-polyline-encoding-tool which (I think but have not tested) provides a class and a CLI tool to do the conversions both ways.
$json = file_get_contents("https://maps.googleapis.com/maps/api/directions/json?origin=20%20%20Kintyre%20Crescent,%20Churchlands&destination=%2018Kinross%20Crescent,%20Churchlands&key=");
$details = json_decode($json,true);
print_r($details); // show the full result
$points = $details['routes'][0]['legs'][0]['steps'][0]['polyline']['points'];
echo($points); // show the points string for one leg
// show the start and end locations for that leg
print_r($details['routes'][0]['legs'][0]['steps'][0]['start_location']);
print_r($details['routes'][0]['legs'][0]['steps'][0]['end_location']);
// work out the intermdiate points (normally used for drawing)
$decodedPoints= decodePolylinePoints($points);
print_r($decodedPoints); // print out the intermediate points
// This function decodes the polylone points in PHP
function decodePolylinePoints($pointsString)
{
$len = strlen($pointsString);
$latLons = array(); // the output array
$lat = 0; // temp storage for lat and lng
$lng = 0;
$index = 0; // index to curent character
while ($index < $len) // process each lat,lng pair
{
// first build the lat
// NOTE: first lat is an absolute value
// NOTE: subsequent lats are offsets from previous values for coding efficiency
$char = 0; // char as read from points string
$shift = 0; // cumulative shift amount
$value = 0; // temp value during computation
do // Read, convert and shift 5 bit chunks until terminator is reached to get lat
{
$char = ord(substr($pointsString, $index++)) - 63; // return ascii value less 63
$value |= ($char & 0x1f) << $shift; // convert to 5 bit and shift left
$shift += 5; // next shift is 5 extra
}
while ($char >= 0x20); // value of 20 indicates end of lat
$lat += (($value & 1) ? ~($value >> 1) : ($value >> 1)); // convert negative values and save
// now build the lng
// NOTE: first lng is an absolute value
// NOTE: subsequent lngs are offsets from previous values for coding efficiency
$shift = 0;
$value = 0;
do // build up lng from 5 bit chunks
{
$char= ord(substr($pointsString, $index++)) - 63; // return ascii value less 63
$value |= ($char & 0x1f) << $shift; // convert to 5 bit and shift left
$shift += 5; // next shift is 5 extra
}
while ($char >= 0x20); // value of 20 indicates end of lng
$lng += (($value & 1) ? ~($value >> 1) : ($value >> 1)); // convert negative values and save
$latLons[] = array($lat * 1e-5, $lng * 1e-5); // original values were * 1e5
}
return $latLons; // points array converted to lat,lngs
}
I have this below code written in PHP responsible for the server socket, specifically by writing messages to certain sockets:
header('Content-Type: text/html; charset=utf-8');
const PAYLOAD_LENGTH_16 = 126;
const PAYLOAD_LENGTH_63 = 127;
const OPCODE_CONTINUATION = 0;
for ($i = 0; $i < $frameCount; $i++) {
// fetch fin, opcode and buffer length for frame
$fin = $i != $maxFrame ? 0 : self::FIN;
$opcode = $i != 0 ? self::OPCODE_CONTINUATION : $opcode;
$bufferLength = $i != $maxFrame ? $bufferSize : $lastFrameBufferLength;
// set payload length variables for frame
if ($bufferLength <= 125) {
$payloadLength = $bufferLength;
$payloadLengthExtended = '';
$payloadLengthExtendedLength = 0;
}
elseif($bufferLength <= 65535) {
$payloadLength = self::PAYLOAD_LENGTH_16;
$payloadLengthExtended = pack('n', $bufferLength);
$payloadLengthExtendedLength = 2;
} else {
$payloadLength = self::PAYLOAD_LENGTH_63;
$payloadLengthExtended = pack('xxxxN', $bufferLength); // pack 32 bit int, should really be 64 bit int
$payloadLengthExtendedLength = 8;
}
// set frame bytes
$buffer = pack('n', (($fin | $opcode) << 8) | $payloadLength).$payloadLengthExtended.substr($message, $i * $bufferSize, $bufferLength);
And below I have the code in Objective-C responsible for receiving these messages from the socket server:
NSInteger len = 0;
uint8_t buffer[4096];
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
[self.data appendBytes:buffer length:len];
[self.log insertText:[NSString stringWithFormat:#"Log: Received a message from server:\n\n"]];
NSLog(#"Received a message from server...");
}
}
when all bytes are received I run the following command to turn the data into a file:
[self.data writeToFile:#"dataComes.txt" options:NSDataWritingAtomic error:nil]
The Problem
We will send a large file in JSON format for objective-c, with that he will receive that information and will generate a file called dataComes.txt, I can see the JSON file normally but except for some strange characters such as:
~ or ~Â or â-Û
These strange characters always shows at the beginning of each block messages that Objective-C receives (Yes, the socket server and TCP divide large messages into blocks of messages).
What is the cause of this problem and how it could solve this?
SOLUTION 1: Filtering
I can filter out unwanted characters that may come, but it will also filter out some words that have accentuation:
NSCharacterSet *notAllowedChars = [[NSCharacterSet characterSetWithCharactersInString:#"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ[]{}:,'"] invertedSet];
NSString *resultString = [[total componentsSeparatedByCharactersInSet:notAllowedChars] componentsJoinedByString:#" "];
SOLUTION 2: Stop using sockets
I have tried many ways to send data to my app, the only one that worked was to send the data separately (a loop of one JSON), but to works I had to put my code (PHP) to sleep using sleep(1) (and I believe this is not good) because if not Objective-C recognizes that this data is a single package.
In this case, or my code have problems, or the programming of socket in objective-c was not very well done and has inconsistencies (bug). What remains for me to do with my connections through normal requests via web server (which I do not think it's a good idea, since I have to do this every 3 seconds in a 5 minute time interval).
SOLUTION 3: FILTERING + UNICODE
On the server side I can filter all special characters and create a specific combination for it example:
Hello é world to Hello /e001/ world
And in my app I can filter this combination and change to the real format....
#include <fstream>
#include <iostream>
using namespace std;
bool find_in_file(char*);
void insert_in_file(char*);
inline bool isNull(char* word);
int main()
{
char word[25];
for(int i = 0; i < 10; i++)
{
cin >> word;
if( find_in_file(word) )
cout << "found" << endl;
else
insert_in_file(word);
}
system("pause");
}
bool find_in_file(char* word)
{
ifstream file;
file.open("file.dat", ios::in);
char contents[655][25] = {0};
file.read(reinterpret_cast<char*>(contents), 16*1024);
file.close();
int i = 0;
while( !isNull(contents[i]) )
{
if( strcmp(contents[i], word) == 0)
return true;
if( strcmp(contents[i], word) < 0 )
i = 2*i + 2;
else
i = 2*i + 1;
}
return false;
}
void insert_in_file(char* word)
{
fstream file;
file.open("file.dat", ios::in | ios::binary);
char contents[655][25] = {0};
file.read(reinterpret_cast<char*>(contents), 16*1024);
file.close();
file.open("file.dat", ios::in | ios::out | ios::binary);
if( isNull(contents[0]) )
{
file.write(word, 25);
file.close();
return;
}
int parent;
int current = 0;
while( !isNull(contents[current]) )
{
parent = current;
if( strcmp( contents[current], word ) < 0 )
current = current*2 + 2;
else if ( strcmp( contents[current], word ) > 0)
current = current*2 + 1;
else
return;
}
int insertAt;
if( strcmp(contents[parent], word ) < 0 )
insertAt = parent*2 + 2;
else
insertAt = parent*2 + 1;
file.seekp(insertAt*25, ios_base::beg);
file.write(reinterpret_cast<const char*>(word), 25);
file.close();
}
inline bool isNull(char* word)
{
return word[0] == 0;
}
The above code implements a binary search tree on file. It uses char arrays of length 25 as nodes. It assumes a size of around 16K as max for the file. The tree is stored in this format:
0 root
1 left child of root - L
2 right child of root - R
3 left child of L - LL
4 right child of L - LR
5 left child of R - RL
6 right child of R - RR
and so on. In the absence of a child, an empty node is inserted. Now I have to do the same thing in PHP. How is it possible since as far as I know, PHP does not provide binary file access. Eagerly looking forward to your responses :)
edit: If I write an integer to file in binary mode, c/c++ will write 4 bytes regardless of the value stored in that integer. PHP will write the plain integer value in file, that is, 0 if the value is 0 and 100 if it is 100. This raises problems when using seek because I dont know the specific number of bytes to move the put pointer. Or in this case, I am writing character arrays of fixed length = 25. How can I do this in php since the variables dont have a type at all?
PHP does provide binary file access. Use fopen() and specify 'b' in the mode field.
To perform random access (i.e. read/write), you should specify 'r+' in the mode field (or 'w+', 'x+' or 'a+', depending on precisely what you want to do).
To actually write binary data (rather than textual representations of that data), use fwrite() and pack().
From php documentation:
In contrast, you can also use 'b' to force binary mode, which will not
translate your data. To use these flags, specify either 'b' or 't' as
the last character of the mode parameter.
What exactly do you mean when you say that php doesn't provide binary file access?
First things first, I'm cheap! :) I can't afford to buy a static IP for my domain and I can't afford those fancy certificates... So no SSL/HTTPS for me.
What I'm trying to accomplish here is to roll-out my own "HTTP encryption". Here's what I have accomplished so far:
Modified an existing proxy script (Glype/PHProxy) to "encrypt" (base64 for now) the echo output. (I'm wrapping the entire content in a body element, btw)
Written a GreaseMonkey script to "decrypt" the encrypted output.
The thing works on simple websites. But when I'm loading complex websites (like a browser game), the javascripts are broken (btw, the script can render the game perfectly when I turned off my encryption).
Upon inspection via FireBug, I've noticed that the contents of the head element is being placed in the body element. This doesn't always happen so I suspected that the PHP is throwing malformed output, but I decoded the base64 using an offline tool and the HTML looks okay.
Here's a sample output from the PHP:
<html><body>PGh0bWw+DQo8aGVhZD4NCjx0aXRsZT5IZWxsbzwvdGl0bGU+DQo8L2hlYWQ+DQo8Ym9keT4NCjxoMT5IZWxsbyBXb3JsZDwvaDE+DQo8L2JvZHk+DQo8L2h0bWw+</body></html>
Here's the decoded HTML from Firebug (after being processed by the GM script):
<html>
<head>
<title>Hello</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
Here's my GM script to decode the PHP output:
function utf8_decode (str_data) {
var tmp_arr = [],
i = 0,
ac = 0,
c1 = 0,
c2 = 0,
c3 = 0;
str_data += '';
while (i < str_data.length) {
c1 = str_data.charCodeAt(i);
if (c1 < 128) {
tmp_arr[ac++] = String.fromCharCode(c1);
i++;
} else if (c1 > 191 && c1 < 224) {
c2 = str_data.charCodeAt(i + 1);
tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = str_data.charCodeAt(i + 1);
c3 = str_data.charCodeAt(i + 2);
tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return tmp_arr.join('');
}
function base64_decode (data) {
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
ac = 0,
dec = "",
tmp_arr = [];
if (!data) {
return data;
}
data += '';
do { // unpack four hexets into three octets using index points in b64
h1 = b64.indexOf(data.charAt(i++));
h2 = b64.indexOf(data.charAt(i++));
h3 = b64.indexOf(data.charAt(i++));
h4 = b64.indexOf(data.charAt(i++));
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
o1 = bits >> 16 & 0xff;
o2 = bits >> 8 & 0xff;
o3 = bits & 0xff;
if (h3 == 64) {
tmp_arr[ac++] = String.fromCharCode(o1);
} else if (h4 == 64) {
tmp_arr[ac++] = String.fromCharCode(o1, o2);
} else {
tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
}
} while (i < data.length);
dec = tmp_arr.join('');
dec = utf8_decode(dec);
return dec;
}
document.documentElement.innerHTML = base64_decode(document.body.innerHTML);
I think the problem is I'm assigning the decoded HTML to document.documentElement.innerHTML, and by doing so it's putting the entire thing inside the body element?
So the question is, what is the correct way to recreate a HTML document from a string?
Since you are just base 64 encoding, and as #Battle_707 has said the issue is with dom events, why don't you send a page that redirects to a data url. This way the browser should fire all the right events.
But seriously, just get a certificate and get on dyndns.com, base 64 buys you no extra security
Edit
Since you mentioned moving to AES, if you can find a JS AES implementation you could use my suggestion here and construct the data URL client side and redirect to that.
function openPageFromString(html){
location="data:text/html,"+encodeURIComponent(html);
}
The problem with, what you refer to as 'complex' pages, is that they have very specific DOM events. These events will be triggered either when the browser reads the line for the first time, or upon certain 'breakpoints' (like 'onload'). Since you obfuscate the code, and then decode it after it has been fully downloaded, your browser won't re-read the page to hit those events. Maybe, just maybe, you could call every function from those events manually after the page has been loaded, but I would not be surprised if (some) browsers will give you a hard time doing that, since the page has been created like <html><head></head><body><html>.....your decoded page....</html></body></html>. This is besides the fact that JS engines might not even index the new code at all.
I'm working on a webapp where I want to match some crc32 values that have been generated server side in PHP with some crc32 values that I am generating in Javascript. Both are using the same input string but returning different values.
I found a crc32 javascript library on webtoolkit, found here. When I try and match a simple CRC32 value that I generate in PHP, for the life of me I can't generate the same matching value in the Javascript crc32 function. I tried adding a utf-8 language encoding meta tag to the top of my page with no luck. I've also tried adding a PHP utf8_encode() around the string before I enter it into the PHP crc32 function, but still no matching crc's ....
Is this a character encoding issue? How do I get these two generated crc's to match? Thanks everyone!
/**
*
* Javascript crc32
* http://www.webtoolkit.info/
*
**/
function crc32 (str) {
function Utf8Encode(string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
};
str = Utf8Encode(str);
var table = "00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D";
if (typeof(crc) == "undefined") { crc = 0; }
var x = 0;
var y = 0;
crc = crc ^ (-1);
for( var i = 0, iTop = str.length; i < iTop; i++ ) {
y = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
x = "0x" + table.substr( y * 9, 8 );
crc = ( crc >>> 8 ) ^ x;
}
return crc ^ (-1);
};
I actually needed this exact same functionality recently for a work project. So this is what I have been able to figure out.
The reason they do not match is because the Javascript implementation is not working on bytes. Using str.charCodeAt(i) will not always return a value 0-255 (in the case of Unicode characters it'll return a potentially much larger number). The Utf8Encode function might be trying to work around this but I don't think it will work for any given binary data.
Using the stringToBytes function from this question: Reading bytes from a JavaScript string will help convert data in a string to bytes. Though I did experience some completely dropped bytes, which seemed more to do with how the string was being stored in the browser than the function itself, it may work in your situation however.
One other hiccup you might have is that PHP's crc32 function will return an unsigned 32bit integer. The above function will return a signed 32bit integer. So given those two things here is the function I ended up with:
crc32 = {
table:"00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D",
//This will probably match php's crc32
genBytes:function(str, crc ) {
var bytes = stringToBytes(str)
if( crc == window.undefined ) crc = 0;
var n = 0; //a number between 0 and 255
var x = 0; //a hex number
crc = crc ^ (-1);
for( var i = 0, iTop = bytes.length; i < iTop; i++ ) {
n = ( crc ^ bytes[i] ) & 0xFF;
x = "0x" + this.table.substr( n * 9, 8 );
crc = ( crc >>> 8 ) ^ x;
}
crc = crc ^ (-1)
//convert to unsigned 32-bit int if needed
if (crc < 0) {crc += 4294967296}
return crc;
}
}
Also if you happen to be using Adobe Air, you can just use a ByteArray and avoid the stringToBytes function.