Encoding puzzles with sockets in different languages - php

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....

Related

Encrypted php code

Issue
I have some PHP code that I've been decrypting (de-obfuscating) for 2 hours. I finally got it converted back into readable code, but I still have some issues understanding the algorithm used here, because of lack of knowledge about some things in the code below.
Code
<?php
$posted = isset($_POST['posted']) ? $_POST['posted'] : (isset($_COOKIE['posted']) ? $_COOKIE['posted'] : NULL);
if ($posted!==NULL) {
$posted= md5($posted) . substr(md5(strrev($posted)), 0, strlen($posted));
for ($counter=0; $counter < 15324; $counter++) {
$idk[$counter] = chr((ord($idk[$counter]) - ord($posted[$counter])) % 256);
$posted.=$idk[$counter];
}
if($idk = #gzinflate($idk)) {
if (isset($_POST['posted']))
#setcookie('posted', $_POST['posted']);
$counter = create_function('', $idk);
unset($idk, $posted);
$counter();
}
}
The $idk variable is already a value that contains a long string that's being base64 decoded.
What I Don't Understand
I understand almost all of the code, but I don't get what % 256 does in here and also I don't know what gzinflate() does.
So, gzinflate() un-compresses input data that is compressed with the zlib DEFLATE algorithm. The corresponding function to compress or deflate an uncompressed string is called gzdeflate(), and it's manual page provides a bit more information:
This function compresses the given string using the DEFLATE data format.
For details on the DEFLATE compression algorithm see the document "DEFLATE Compressed Data Format Specification version 1.3" (RFC 1951). Sparing a few details, this is similar to compressing a file using gzip myfile.txt on the Linux command line, which would create the compressed file myfile.txt.gz. In short, this is uncompressing compressed data assigned to $idk.
$variable % 256 returns the remainder of dividing $variable by 256. If I set $variable to 258, $variable % 256 would be 2. This is often used when you want to see if a number is cleanly-divisible by another number. If I wanted to show a status-update every 100 times of a loop, for example, I might do:
<?php
for ($i = 1; $i <= 1000; ++$i)
{
// Do something on each loop.
if (($i % 100) == 0)
{
echo sprintf("Loop %d of 1000; %d percent complete.\n", $i, $i / 1000 * 100);
}
}
But there are obviously many other uses.
As far as helping you figure out what exactly this source code does, I would recommend going through it step-by-step with real input and seeing what happens after each step. It will be hard for me to figure out much more about what it's doing without a lot more context.

Avoiding 500 line limit exceeded error while sending emails

I am using the PHPMailer library integrated in Joomla for an email component in Joomla. It does work quite well, however I am having an issue with users running the script with 1and1 mail servers. They can get errors like that:
2012-06-14 18:20:34 u65913791 1x1et0-1RocCH2xzU-00qzkq EE transaction error after sending of mail text: msmtp.kundenserver.de[172.19.35.7] 500 Line limit exceeded
Another example from a different user:
SMTP error from remote mail server after end of data:
host mx00.1and1.co.uk [212.227.15.134]: 500 Line limit exceeded
The line limit is not about how many lines but how many characters are actually used in a single line which 1and1 limits to 10240 characters (support answer) - which is actually 10 times more than required in RFC 2822.
I assume the issue is caused by using "wrong" line seperators when the emails is submitted so that the whole email reaches the email server as a single line. I guess that I need to make sure to insert line breaks in my script as PHPMailer fails do so.
Currently I am just receiving the HTML content from a WYSIWYG-editor and put into the PHPMailer object:
// snip, $mail2send is the JMail instance, which inherits PHPMailer
$mail2send->setSubject($mail->subject);
$mail2send->IsHTML(true);
$mail2send->setBody($mail->body);
// snip
How can I insert the appropiate line breaks?
Use chunk_split. This function was designed for tasks like yours and even its default (split at 76 chars) says so.
So your code will be
$mail2send->setSubject($mail->subject);
$mail2send->IsHTML(true);
$mail2send->setBody(chunk_split($mail->body));
Convert to a content transfer encoding such as base64 or quoted-printable, both of which have been devised for encapsulating free-form data. QP is more efficient for predominantly US-ASCII data with the occasional 8-bit character and/or overlong lines.
Of course, if your data is HTML and it is otherwise safe for SMTP, merely adding line terminators where you otherwise have whitespace is a slightly brittle workaround (are you sure you don't have a line-initial "From" anywhere, etc?)
After further investigation the error could be identified: after several replies in an email thread an embedded HTML message had no lines break anymore. I guess an email client involved in the conversation did this.
To overcome this problem I do a HTML-tag-safe wrapping using the following function:
/* HTML-tag-safe wordwrap
* from http://php.net/manual/de/function.wordwrap.php
* by nbenitezl[arroba]gmail[dot]com
*/
function htmlwrap(&$str, $maxLength=76, $char="\r\n"){
$count = 0;
$newStr = '';
$openTag = false;
$lenstr = strlen($str);
for($i=0; $i<$lenstr; $i++){
$newStr .= $str{$i};
if($str{$i} == '<'){
$openTag = true;
continue;
}
if(($openTag) && ($str{$i} == '>')){
$openTag = false;
continue;
}
if(!$openTag){
if($str{$i} == ' '){
if ($count == 0) {
$newStr = substr($newStr,0, -1);
continue;
} else {
$lastspace = $count + 1;
}
}
$count++;
if($count==$maxLength){
if ($str{$i+1} != ' ' && $lastspace && ($lastspace < $count)) {
$tmp = ($count - $lastspace)* -1;
$newStr = substr($newStr,0, $tmp) . $char . substr($newStr,$tmp);
$count = $tmp * -1;
} else {
$newStr .= $char;
$count = 0;
}
$lastspace = 0;
}
}
}
return $newStr;
}

PHP (ZLIB) uncompression of a C (ZLIB) compressed array returns gibberish

I have a set of ZLIB compressed / base64 encoded strings (done in a C program) that are stored in a database. I have written a small PHP page that should retrieve these values and plot them (the string originally was a list of floats).
Chunk of C program that compresses/encodes:
error=compress2(comp_buffer, &comp_length,(const Bytef*)data.mz ,(uLongf)length,Z_DEFAULT_COMPRESSION); /* compression */
if (error != Z_OK) {fprintf(stderr,"zlib error..exiting"); exit(EXIT_FAILURE);}
mz_binary=g_base64_encode (comp_buffer,comp_length); /* encoding */
(Example) of original input format:
292.1149 8379.5928
366.1519 101313.3906
367.3778 20361.8105
369.1290 17033.3223
375.4355 1159.1841
467.3191 8445.3926
Each column was compressed/encoded as a single string. To reconstruct the original data i am using the following code:
//$row[4] is retrieved from the DB and contains the compressed/encoded string
$mz = base64_decode($row[4]);
$unc_mz = gzuncompress($mz);
echo $unc_mz;
Yet this gives me the following output:
f6jEÍ„]EšiSE#IEfŽ
Could anyone give me a tip/hint about what I might be missing?
------ Added Information -----
I feel that the problem comes from the fact that currently php views $unc_mz as a single string while in reality i would have to re-construct an array containing X lines (this output was from a 9 line file) but... no idea how to do that assignment.
The C program that did that went roughly like this:
uncompress( pUncompr , &uncomprLen , (const Bytef*)pDecoded , decodedSize );
pToBeCorrected = (char *)pUncompr;
for (n = 0; n < (2 * peaksCount); n++) {
pPeaks[n] = (RAMPREAL) ((float *) pToBeCorrected)[n];
}
where peaksCount would be the amount of 'lines' in the input file.
EDIT (15-2-2012): The problem with my code was that I was not reconstructing the array, the fixed code is as follows (might be handy if someone needs a similar snippet):
while ($row = mysql_fetch_array($result, MYSQL_NUM)) {
$m< = base64_decode($row[4]);
$mz_int = gzuncompress($int);
$max = strlen($unc_mz);
$counter = 0;
for ($i = 0; $i < $max; $i = $i + 4) {
$temp= substr($unc_mz,$i,4);
$temp = unpack("f",$temp);
$mz_array[$counter] = $temp[1];
$counter++;
}
The uncompressed string has to be chopped into chunks corresponding to the length of a float, unpack() then reconstructs the float data from teh binary 'chunk'. That's the simplest description that I can give for the above snippet.
compress2() produces the zlib format (RFC 1950). I would have to guess that something called gzuncompress() is expecting the gzip format (RFC 1952). So gzuncompress() would immediately fail upon not finding a gzip header.
You would need to use deflateInit2() in zlib to request that deflate() produce gzip-formatted output, or find or provide a different function in PHP that expects the zlib format.

best way to detect number of SMS needed to send a text

I'm looking for a code/lib in php that I will call it and pass a text to it and it will tell me:
What is the encode I need to use in order to send this text as SMS (7,8,16 bit)
How many SMS message I will use to send this text (it must be smart to count "segmenation information" like in http://ozekisms.com/index.php?owpn=612)
do you have any idea of any code/lib exists that will do this for me?
Again I'm not looking for sending SMS or converting SMS, just to give me information about the text
Update:
Ok I did the below code and it seems to be working fine, let me know if you have better/optimized code/solution/lib
$text = '\#£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ -./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà^{}[~]|€' ; //"\\". //'"';//' ';
print $text . "\n";
print isGsm7bit($text). "\n";
print getNumberOfSMSsegments($text). "\n";
function getNumberOfSMSsegments($text,$MaxSegments=6){
/*
http://en.wikipedia.org/wiki/SMS
Larger content (concatenated SMS, multipart or segmented SMS, or "long SMS") can be sent using multiple messages,
in which case each message will start with a user data header (UDH) containing segmentation information.
Since UDH is part of the payload, the number of available characters per segment is lower:
153 for 7-bit encoding,
134 for 8-bit encoding and
67 for 16-bit encoding.
The receiving handset is then responsible for reassembling the message and presenting it to the user as one long message.
While the standard theoretically permits up to 255 segments,[35] 6 to 8 segment messages are the practical maximum,
and long messages are often billed as equivalent to multiple SMS messages. See concatenated SMS for more information.
Some providers have offered length-oriented pricing schemes for messages, however, the phenomenon is disappearing.
*/
$TotalSegment=0;
$textlen = mb_strlen($text);
if($textlen==0) return false; //I can see most mobile devices will not allow you to send empty sms, with this check we make sure we don't allow empty SMS
if(isGsm7bit($text)){ //7-bit
$SingleMax=160;
$ConcatMax=153;
}else{ //UCS-2 Encoding (16-bit)
$SingleMax=70;
$ConcatMax=67;
}
if($textlen<=$SingleMax){
$TotalSegment = 1;
}else{
$TotalSegment = ceil($textlen/$ConcatMax);
}
if($TotalSegment>$MaxSegments) return false; //SMS is very big.
return $TotalSegment;
}
function isGsm7bit($text){
$gsm7bitChars = "\\\#£\$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà^{}[~]|€";
$textlen = mb_strlen($text);
for ($i = 0;$i < $textlen; $i++){
if ((strpos($gsm7bitChars, $text[$i])==false) && ($text[$i]!="\\")){return false;} //strpos not able to detect \ in string
}
return true;
}
I'm adding some extra information here because the previous answer isn't quite correct.
These are the issues:
You need to be specifying the current string encoding to mb_string, otherwise this may be incorrectly gathered
In 7-bit GSM encoding, the Basic Charset Extended characters (^{}\[~]|€) require 14-bits each to encode, so they count as two characters each.
In UCS-2 encoding, you have to be wary of emoji and other characters outside the 16-bit BMP, because...
GSM with UCS-2 counts 16-bit characters, so if you have a 💩 character (U+1F4A9), and your carrier and phone sneakily support UTF-16 and not just UCS-2, it will be encoded as a surrogate pair of 16-bit characters in UTF-16, and thus be counted as TWO 16-bit characters toward your string length. mb_strlen will count this as a single character only.
How to count 7-bit characters:
What I've come up with so far is the following to count 7-bit characters:
// Internal encoding must be set to UTF-8,
// and the input string must be UTF-8 encoded for this to work correctly
protected function count_gsm_string($str)
{
// Basic GSM character set (one 7-bit encoded char each)
$gsm_7bit_basic = "#£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà";
// Extended set (requires escape code before character thus 2x7-bit encodings per)
$gsm_7bit_extended = "^{}\\[~]|€";
$len = 0;
for($i = 0; $i < mb_strlen($str); $i++) {
$c = mb_substr($str, i, 1);
if(mb_strpos($gsm_7bit_basic, $c) !== FALSE) {
$len++;
} else if(mb_strpos($gsm_7bit_extended, $c) !== FALSE) {
$len += 2;
} else {
return -1; // cannot be encoded as GSM, immediately return -1
}
}
return $len;
}
How to count 16-bit characters:
Convert the string into UTF-16 representation (to preserve the emoji characters with mb_convert_encoding($str, 'UTF-16', 'UTF-8').
do not convert into UCS-2 as this is lossy with mb_convert_encoding)
Count bytes with count(unpack('C*', $utf16str)) and divide by two to get the number of UCS-2 16-bit characters that count toward the GSM multipart length
*caveat emptor, a word on counting bytes:
Do not use strlen to count the number of bytes. While it may work, strlen is often overloaded in PHP installations with a multibyte-capable version, and is also a candidate for API change in the future
Avoid mb_strlen($str, 'UCS-2'). While it does currently work, and will return, correctly, 2 for a pile of poo character (as it looks like two 16-bit UCS-2 characters), its stablemate mb_convert_encoding is lossy when converting from >16-bit to UCS-2. Who's to say that mb_strlen won't be lossy in the future?
Avoid mb_strlen($str, '8bit') / 2. It also currently works, and is recommended in a PHP docs comment as a way to count bytes. But IMO it suffers from the same issue as the above UCS-2 technique.
That leaves the safest current way (IMO) as unpacking into a byte array, and counting that.
So, what does this look like?
// Internal encoding must be set to UTF-8,
// and the input string must be UTF-8 encoded for this to work correctly
protected function count_ucs2_string($str)
{
$utf16str = mb_convert_encoding($str, 'UTF-16', 'UTF-8');
// C* option gives an unsigned 16-bit integer representation of each byte
// which option you choose doesn't actually matter as long as you get one value per byte
$byteArray = unpack('C*', $utf16str);
return count($byteArray) / 2;
}
Putting it all together:
function multipart_count($str)
{
$one_part_limit = 160; // use a constant i.e. GSM::SMS_SINGLE_7BIT
$multi_limit = 153; // again, use a constant
$max_parts = 3; // ... constant
$str_length = count_gsm_string($str);
if($str_length === -1) {
$one_part_limit = 70; // ... constant
$multi_limit = 67; // ... constant
$str_length = count_ucs2_string($str);
}
if($str_length <= $one_part_limit) {
// fits in one part
return 1;
} else if($str_length > ($max_parts * $multi_limit) {
// too long
return -1; // or throw exception, or false, etc.
} else {
// divide the string length by multi_limit and round up to get number of parts
return ceil($str_length / $multi_limit);
}
}
Turned this into a library...
https://bitbucket.org/solvam/smstools
The best solution I have so far:
$text = '\#£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ -./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà^{}[~]|€' ; //"\\". //'"';//' ';
print $text . "\n";
print isGsm7bit($text). "\n";
print getNumberOfSMSsegments($text). "\n";
function getNumberOfSMSsegments($text,$MaxSegments=6){
/*
http://en.wikipedia.org/wiki/SMS
Larger content (concatenated SMS, multipart or segmented SMS, or "long SMS") can be sent using multiple messages,
in which case each message will start with a user data header (UDH) containing segmentation information.
Since UDH is part of the payload, the number of available characters per segment is lower:
153 for 7-bit encoding,
134 for 8-bit encoding and
67 for 16-bit encoding.
The receiving handset is then responsible for reassembling the message and presenting it to the user as one long message.
While the standard theoretically permits up to 255 segments,[35] 6 to 8 segment messages are the practical maximum,
and long messages are often billed as equivalent to multiple SMS messages. See concatenated SMS for more information.
Some providers have offered length-oriented pricing schemes for messages, however, the phenomenon is disappearing.
*/
$TotalSegment=0;
$textlen = mb_strlen($text);
if($textlen==0) return false; //I can see most mobile devices will not allow you to send empty sms, with this check we make sure we don't allow empty SMS
if(isGsm7bit($text)){ //7-bit
$SingleMax=160;
$ConcatMax=153;
}else{ //UCS-2 Encoding (16-bit)
$SingleMax=70;
$ConcatMax=67;
}
if($textlen<=$SingleMax){
$TotalSegment = 1;
}else{
$TotalSegment = ceil($textlen/$ConcatMax);
}
if($TotalSegment>$MaxSegments) return false; //SMS is very big.
return $TotalSegment;
}
function isGsm7bit($text){
$gsm7bitChars = "\\\#£\$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà^{}[~]|€";
$textlen = mb_strlen($text);
for ($i = 0;$i < $textlen; $i++){
if ((strpos($gsm7bitChars, $text[$i])==false) && ($text[$i]!="\\")){return false;} //strpos not able to detect \ in string
}
return true;
}
page 1 : 160 byte
page 2 : 146 byte
page 3 : 153 byte
page 4 : 153 byte
page 5 : 153 byte, ....
So regardless of language :
// strlen($text) show bytes
$count = 0;
$len = strlen($text);
if ($len > 306) {
$len = $len - 306;
$count = floor($len / 153) + 3;
} else if($len>160){
$count = 2;
}else{
$count = 1;
}

Translate Code: C Socket to PHP Socket

I looked through past threads on here to find any relevant topics regarding C sockets being translated to PHP sockets, and I've ready extensively on php.net and C tutorials to figure out how to convert some C source code I have into PHP source code involving a remote socket connection.
The source I am going to post is in C. This code is already working and confirmed to work in a compiled .exe that one of my programmers wrote. He doesn't know PHP, which I am creating this new program in that requires this snippet.
The program does this: It creates a socket connection to a remote server/port, sends the filesize of an image that it needs to send to the server, then I am guessing when the server knows the filesize, the program sends the binary image data and the filesize of the image again (like an upload feature to the server via sockets). Then it uses the recv(); function in C to receive the bytes back of a specific length.
Basically it is sending a picture with something encrypted inside of it. The server already has a program running on it on the specified port that is decrypting the image. Then the socket is sending back that decrypted text. I do not have access to the algorithm for decryption otherwise I would not be using sockets obviously.
Here is the C source I was sent, and my subsequent attempts in PHP to translate it properly.
// In the this C code, there is the long size; variable that is used at the bottom but is never initialized. I don't know what to do with it. Some other variables are never used either.
function picBin()
assume curlBinaryData variable pic is filled with binary data from picture download.
pic->currentSize is set to the size of the image
it will return 0 if successful. also char *word in the function's params will be set to the pic's decryption
//bin data structure i use for a quick ghetto download function, just so you know how it looks
struct curlBinaryData{
char *data;
int currentSize;
int maxSize;
};
int picBin(curlBinaryData *pic, char *word, int threadNum,
char *host, unsigned short port)
{
char data1[1000], data2[1000],
temp[1000], printBuf[1000], buffer[1000], *p, *p2;
int num, a, totalBytes;
long size;
char *pSize;
SOCKET sock;
while ((sock = connectSocket(host, port)) == INVALID_SOCKET)
{
sprintf(printBuf, "Could not connect(picBin) %s:%d\n", host, port);
print_ts(printBuf, "red");
//Sleep(15000);
}
buffer[0]='\0';
send(sock, buffer, 1, 0);
pSize=(char *)&(pic->currentSize);
send(sock, pSize, 4, 0);
send(sock, pic->data, pic->currentSize, 0);
totalBytes=0;
do{
if ( (num=recv(sock, data1+totalBytes, 1, 0)) > 0)
totalBytes+=num;
} while( (totalBytes<4) && (num>0) );
pSize=(char *)&size;
if (totalBytes==4){ //got 4 bytes for dword
memcpy(pSize, data1, 4);
if (size==1)
{
totalBytes=0;
do
{
if ( (num=recv(sock, data1+totalBytes, 1, 0)) > 0)
totalBytes+=num;
} while( (totalBytes<4) && (num>0) );
memcpy(pSize, data1, 4);
if (totalBytes==4)
{ //got 4 bytes for dword
totalBytes=0;
for (a=0; ( (a<size) && (num>0) ); a++)
{
if ( (num=recv(sock, data1+totalBytes, 1, 0)) > 0)
totalBytes+=num;
}
if (totalBytes==size)
{
closesocket(sock);
data1[totalBytes]='\0';
strcpy(word, data1);
return 0; //0 on success
}
}
}
}
closesocket(sock);
return -1; //something errord
}
Now here is my PHP code I attempted:
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false)
{
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}
if (socket_connect($sock, $host, $port) === false)
{
echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
socket_send($sock, '\0', 1, MSG_EOF);
$ci = file_get_contents($picURL);
$ciwrite = fopen('pic.jpg', 'w+');
fwrite($ciwrite, $ci);
fclose($ciwrite);
$picFileSize = filesize('pic.jpg');
socket_send($sock, $picFileSize, 4, MSG_EOF);
socket_send($sock, $ci, $picFileSize, MSG_EOF);
$num = socket_recv($sock, $totalBytes, 1, MSG_DONTWAIT);
print $num; // this doesn't even Print anything to my console when I execute it via CLI
/*do{
if (($num = socket_recv($sock, $totalBytes, 1)) > 0)
{
$totalBytes += $num;
}
} while(($totalBytes < 4) && ($num > 0));*/
buffer[0]='\0';
send(sock, buffer, 1, 0);
socket_send($sock, '\0', 1, MSG_EOF);
Backslash escape sequences other than \' and \\ are not expanded in single quoted strings; thus, '\0' is a string of the two characters \ and 0, and the above socket_send() sends the character \.
MSG_EOF is without effect at best and harmful at worst; better don't use it.
A correct translation is:
socket_send($sock, "\0", 1, 0);
pSize=(char *)&(pic->currentSize);
send(sock, pSize, 4, 0);
socket_send($sock, $picFileSize, 4, MSG_EOF);
The above socket_send() sends the first 4 characters of the ASCII string representation of $picFileSize, because socket_send() expects a string as its second argument and thus the given integer is coerced into a string. To send a 4-byte binary integer:
socket_send($sock, pack("L", $picFileSize), 4, 0);
$num = socket_recv($sock, $totalBytes, 1, MSG_DONTWAIT);
print $num; // this doesn't even Print anything to my console when I execute it via CLI
It's no wonder that you get no data if you DONTWAIT for it.
A working translation for the receive part of the C program is:
$totalBytes = socket_recv($sock, $data1, 4, MSG_WAITALL);
if ($totalBytes==4)
{ //got 4 bytes for dword
$size = unpack("L", $data1);
if ($size[1]==1)
{
$totalBytes = socket_recv($sock, $data1, 4, MSG_WAITALL);
if ($totalBytes==4)
{ //got 4 bytes for dword
$size = unpack("L", $data1);
$totalBytes = socket_recv($sock, $data1, $size[1], MSG_WAITALL);
if ($totalBytes==$size[1])
{
echo $data1, "\n";
}
}
}
}
regarding C sockets being translated to PHP sockets
Sockets are implemented by the OS - not the language. There is no such thing as a C socket nor a PHP socket.
When you invoke socket_send from PHP it converts the message to a string (if it's not already one).
pSize=(char *)&(pic->currentSize);
send(sock, pSize, 4, 0);
WTF? Assuming that pic->currentSize contains a string represenation if the image why is it hard coded to 4 bytes!
But here:
send(sock, pic->data, pic->currentSize, 0);
pic->currentSize must contain an integer value. Shoving (char *) in front of a pointer to an integer (or a long, since that appears to be how 'size' is declared) DOES NOT MAKE IT a string. It's still a pointer. OK a 32 bit pointer will be 4 bytes - but WTF is a pointer being sent over a socket??? Unless there's some weird overloading going on here and this is actually C++ rather than C.
Reading further on it sends the pointer to the remote end then reads back a 4 byte value and considers the operation successful if it matches the pointer....!! AAARRGGHHH! even if it were sending the size, this level of integrity checking is entirely redundant over a Unix or INET socket.
I'd dig some more but it's going to be a waste of time trying to make sense of this C code. Use a network sniffer to work out what's really happenning here; do not use this C code as any sort of model of how to write your own client.

Categories