📄 mmsdecoder.php
字号:
case RESPONSE_STATUS:
$this->RESPONSESTATUS = $this->data[$this->pos++];
if (DEBUG) $this->debug("Response-status", $this->RESPONSESTATUS);
break;
case RESPONSE_TEXT: /* Encoded string value */
$this->RESPONSETEXT = $this->parseEncodedStringValue();
if (DEBUG) $this->debug("Response-text", $this->RESPONSETEXT);
break;
case SENDER_VISIBILITY: /* Hide | show */
$this->SENDERVISIBILITY = $mmsYesNo[ $this->data[$this->pos++] ];
if (DEBUG) $this->debug("Sender-visibility", $this->SENDERVISIBILITY);
break;
case STATUS:
$this->STATUS = $this->data[$this->pos++];
if (DEBUG) $this->debug("Status", $this->STATUS);
break;
case SUBJECT:
$this->SUBJECT = $this->parseEncodedStringValue();
if (DEBUG) $this->debug("Subject", $this->SUBJECT);
break;
case TO:
$this->TO = $this->parseEncodedStringValue();
if (DEBUG) $this->debug("To", $this->TO);
break;
case TRANSACTION_ID:
$this->TRANSACTIONID = $this->parseTextString();
if (DEBUG) $this->debug("Transaction-id", $this->TRANSACTIONID);
break;
default:
if ($this->data[$this->pos - 1] > 127)
$this->debug("Parse error", "Unknown field (" . $this->data[$pos-1] . ")!", $this->pos-1);
else
debug("Parse error:", "Value encountered when expecting field!", $this->pos);
break;
}
return true;
}
/*---------------------------------------------------------------------*
* Function called after header has been parsed. This function fetches *
* the different parts in the MMS. Returns true until it encounter end *
* of data. *
*---------------------------------------------------------------------*/
function parseParts() {
global $mmsContentTypes; // for parsing the contenttypes
if (!array_key_exists($this->pos, $this->data))
return 0;
// get number of parts
$count = $this->parseUint();
if (DEBUG) $this->debug("MMS parts", $count);
for ($i = 0; $i < $count; $i++) {
// new part, so clear the old data and header
$data = "";
$header = "";
unset($ctype);
// get header and data length
$headerlen = $this->parseUint();
$datalen = $this->parseUint();
/* PARSE CONTENT-TYPE */
// this is actually the same structure as in the MMS content-type
// so maybe we should make this in a better way, but for now, I'll
// just cut n paste
// right now I just save the position in the MMS data array before I parse
// the content-type, to be able to roll back after it has been parsed beacause
// the headerlen includes both the content-type and the header
// TODO: this is just a fast hack and shoul be done in a more proper way
$ctypepos = $this->pos;
if ($this->data[$this->pos] <= 31) { /* Content-general-form */
// the value follows after the current byte and is "current byte" long
$len = $this->parseValueLength();
// check if next byte is in range of 32-127. Then we have a Extension-media which is a textstring
if ($this->data[$this->pos] > 31 && $this->data[$this->pos] < 128)
$ctype = $this->parseTextString();
else {
// we have Well-known-media; which is an integer
$ctype = $mmsContentTypes[$this->parseIntegerValue()];
}
} elseif ($this->data[$this->pos] < 128) { /* Constrained-media - Extension-media*/
//$this->pos++;
$ctype = $this->parseTextString();
} else /* Constrained-media - Short Integer */
$ctype = $mmsContentTypes[$this->parseShortInteger()];
// roll back position so it's just before the content-type again
$this->pos = $ctypepos;
/* END OF CONTENT TYPE */
// Read header. Actually, we don't do anything with this yet.. just skipping it (note that the content-type is included in the header)
for ($j = 0; $j < $headerlen; $j++)
$header .= chr($this->data[$this->pos++]);
// read data
for ($j = 0; $j < $datalen; $j++)
$data .= chr($this->data[$this->pos++]);
if (DEBUG) $this->debug("Part ($i):headerlen", $headerlen);
if (DEBUG) $this->debug("Part ($i):datalen", $datalen);
if (DEBUG) $this->debug("Part ($i):content-type", $ctype);
//if (DEBUG) $this->debug("Part ($i):data", $data); // I've commented this one, to get a cleaner debug
$this->PARTS[] = new MMSPart($headerlen, $datalen, $ctype, $header, $data);
}
return false;
}
/*-------------------------------------------------------------------*
* Parse message-class *
* message-class-value = Class-identifier | Token-text *
* Class-idetifier = Personal | Advertisement | Informational | Auto *
*-------------------------------------------------------------------*/
function parseMessageClassValue() {
if ($this->data[$this->pos] > 127) {
// the byte is one of these 128=personal, 129=advertisement, 130=informational, 131=auto
return $this->data[$this->pos++];
} else
return $this->parseTextString();
}
/*----------------------------------------------------------------*
* Parse Text-string *
* text-string = [Quote <Octet 127>] text [End-string <Octet 00>] *
*----------------------------------------------------------------*/
function parseTextString() {
// Remove quote
if ($this->data[$this->pos] == 0x7F)
$this->pos++;
while ($this->data[$this->pos])
$str .= chr($this->data[$this->pos++]);
$this->pos++;
return $str;
}
/*------------------------------------------------------------------------*
* Parse Encoded-string-value *
* *
* Encoded-string-value = Text-string | Value-length Char-set Text-string *
* *
*------------------------------------------------------------------------*/
function parseEncodedStringValue() {
if ($this->data[$this->pos] < 32) {
$len = $this->parseValueLength();
$this->pos++;
for ($i = 0; $i < $len-1; $i++)
$str .= chr( $this->data[$this->pos++] );
return $str;
} else
return $this->parseTextString();
}
/*--------------------------------------------------------------------------------*
* Parse Value-length *
* Value-length = Short-length<Octet 0-30> | Length-quote<Octet 31> Length<Uint> *
* *
* A list of content-types of a MMS message can be found here: *
* http://www.wapforum.org/wina/wsp-content-type.htm *
*--------------------------------------------------------------------------------*/
function parseValueLength() {
if ($this->data[$this->pos] < 31) {
// it's a short-length
return $this->data[$this->pos++];
} elseif ($this->data[$this->pos] == 31) {
// got the quote, length is an Uint
$this->pos++;
return $this->parseUint();
} else {
// uh, oh... houston, we got a problem
die("Parse error: Short-length-octet (" . $this->data[$this->pos] . ") > 31 in Value-length at offset " . $this->pos . "!\n");
}
}
/*--------------------------------------------------------------------------*
* Parse Long-integer *
* Long-integer = Short-length<Octet 0-30> Multi-octet-integer<1*30 Octets> *
*--------------------------------------------------------------------------*/
function parseLongInteger() {
// Get the number of octets which the long-integer is stored in
$octetcount = $this->data[$this->pos++];
// Error checking
if ($octetcount > 30)
die("Parse error: Short-length-octet (" . $this->data[$this->pos-1] . ") > 30 in Long-integer at offset " . $this->pos-1 . "!\n");
// Get the long-integer
for ($i = 0; $i < $octetcount; $i++) {
$longint = $longint << 8;
$longint += $this->data[$this->pos++];
}
return $longint;
}
/*------------------------------------------------------------------------*
* Parse Short-integer *
* Short-integer = OCTET *
* Integers in range 0-127 shall be encoded as a one octet value with the *
* most significant bit set to one, and the value in the remaining 7 bits *
*------------------------------------------------------------------------*/
function parseShortInteger() {
return $this->data[$this->pos++] & 0x7F;
}
/*-------------------------------------------------------------*
* Parse Integer-value *
* Integer-value = short-integer | long-integer *
* *
* This function checks the value of the current byte and then *
* calls either parseLongInt() or parseShortInt() depending on *
* what value the current byte has *
*-------------------------------------------------------------*/
function parseIntegerValue() {
if ($this->data[$this->pos] < 31)
return $this->parseLongInteger();
elseif ($this->data[$this->pos] > 127)
return $this->parseShortInteger();
else {
$this->debug('ERROR', 'Not a IntegerValue field', $this->pos);
$this->pos++;
return 0;
}
}
/*------------------------------------------------------------------*
* Parse Unsigned-integer *
* *
* The value is stored in the 7 last bits. If the first bit is set, *
* then the value continues into the next byte. *
* *
* http://www.nowsms.com/discus/messages/12/522.html *
*------------------------------------------------------------------*/
function parseUint() {
//if (!($this->data[$this->pos] & 0x80))
// return $this->data[$this->pos++] & 0x7F;
while ($this->data[$this->pos] & 0x80) {
// Shift the current value 7 steps
$uint = $uint << 7;
// Remove the first bit of the byte and add it to the current value
$uint |= $this->data[$this->pos++] & 0x7F;
}
// Shift the current value 7 steps
$uint = $uint << 7;
// Remove the first bit of the byte and add it to the current value
$uint |= $this->data[$this->pos++] & 0x7F;
return $uint;
}
/**
* Send an OK response to the sender after the MMS has been recieved
* See "6.1.2. Send confirmation" in the wap-209-mmsencapsulation specification, on how this is constructed
*/
function confirm() {
$pos = 0;
$confirm[$pos++] = 0x8C; // message-type
$confirm[$pos++] = 129; // m-send-conf
$confirm[$pos++] = 0x98; // transaction-id
for ($i = 0; $i < strlen($this->TRANSACTIONID); $i++)
$confirm[$i+$pos] = ord(substr($this->TRANSACTIONID, $i, 1));
$pos += $i;
$confirm[$pos++] = 0x00; // end of string
$confirm[$pos++] = 0x8D; // version
$confirm[$pos++] = 0x90; // 1.0
$confirm[$pos++] = 0x92; // response-status
$confirm[$pos] = 128; // OK
// respond with the m-send-conf
foreach ($confirm as $byte)
echo chr($byte);
}
/*---------------------------------------*
* Function which outputs debug messages *
*---------------------------------------*/
function debug($name, $str, $pos = -1, $errorlevel = 0) {
if ($pos != -1)
echo "<b>$name ($pos):</b> " . $str;
else
echo "<b>$name:</b> " . $str;
echo "<br>\n";
if ($errorlevel > 0)
exit;
}
/*------------------------------------------*
* Function to output a part of the mmsdata *
* in HEX form, and mark one byte with a ^ *
*------------------------------------------*/
function debughex($start, $count, $markstart = -1, $markcount = -1) {
$hexcount = 0;
$markstop = $markstart + $markcount;
// set font so that the hex will be more readable
echo '<br><font face="fixedsys" size="-1">';
// loop thru data and print hex
for ($i = $start; $i <= ($start+$count); $i++) {
// fix marking
if ($i == $markstart)
echo '<font color="#ff0000">';
if ($i == $markstop)
echo '</font>';
$hex = dechex($this->data[$i]);
// add 0 before hex if needed
if (strlen($hex) < 2)
$hex = '0' . $hex;
// add space
$hex = ' ' . $hex;
// check hexcount, wrap lines if needed etc
if ($hexcount == 8)
echo ' | ';
elseif ($hexcount == 16) {
echo '<br>';
$hexcount = 0;
}
$hexcount++;
echo $hex;
}
// som more html
echo '</font><br><br>';
}
}
/*---------------------------------------------------------------------*
* The MMS part class *
* An instance of this class contains the one parts of an MMS message. *
* *
* The multipart type is formed as: *
* number |part1|part2|....|partN *
* where part# is formed by headerlen|datalen|contenttype|headers|data *
*---------------------------------------------------------------------*/
class MMSPart {
var $headerlen;
var $header;
var $DATALEN;
var $CONTENTTYPE;
var $DATA;
/*----------------------------------*
* Constructor, just store the data *
*----------------------------------*/
function MMSPart($headerlen, $datalen, $ctype, $header, $data) {
$this->hpos = 0;
$this->headerlen = $headerlen;
$this->DATALEN = $datalen;
$this->CONTENTTYPE = $ctype;
$this->DATA = $data;
}
/*-------------------------------------*
* Save the data to a location on disk *
*-------------------------------------*/
function save($filename) {
$fp = fopen($filename, 'wb');
fwrite($fp, $this->DATA);
fclose($fp);
}
}
?>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -