Commit 63ba8bea authored by Sebastian Kummer's avatar Sebastian Kummer

Merge pull request #111 in ZP/z-push from feature/ZP-797-rework-wbxml-handling to develop

* commit '52162fde':
  ZP-797 Fixed WBXML class constant.
  ZP-797 GetAttachment use fpassthru (more efficient).
  ZP-797 WBXMLDecoder is handling ActiveSync WBXML, which is only a subset of WBXML.
  ZP-797 WBXML{En,De}coder: use const instead of define for WBXML_* constants.
  ZP-797 WBXMLDecoder->getOpaque() use stream_get_contents().
  ZP-797 WBXMLDecoder->GetPlainInputStream() use stream_get_contents().
  ZP-797 WBXMLDecoder->_getToken() speedup.
  ZP-797 WBXMLDecoder->getTermStr(): use stream_get_line().
  ZP-797 WBXMLEncoder remove possible endless loop/improve multipart handling.
  ZP-797 WBXMLEncoder remove _outlog / use output buffering.
  ZP-797 WBXMLDecoder remove inlog / reread php://input.
parents f49acb93 52162fde
......@@ -66,20 +66,13 @@ class GetAttachment extends RequestProcessor {
throw new StatusException(sprintf("HandleGetAttachment(): No stream resource returned by backend for attachment: %s", $attname), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT);
header("Content-Type: application/octet-stream");
$l = 0;
while (!feof($stream)) {
$d = fgets($stream, 4096);
$l += strlen($d);
echo $d;
// announce an update every 100K
if (($l/1024) % 100 == 0)
self::$topCollector->AnnounceInformation(sprintf("Streaming attachment: %d KB sent", round($l/1024)));
}
self::$topCollector->AnnounceInformation("Starting attachment streaming", true);
$l = fpassthru($stream);
fclose($stream);
self::$topCollector->AnnounceInformation(sprintf("Streamed %d KB attachment", $l/1024), true);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("HandleGetAttachment(): attachment with %d KB sent to mobile", $l/1024));
if ($l === false)
throw new FatalException("HandleGetAttachment(): fpassthru === false !!!");
self::$topCollector->AnnounceInformation(sprintf("Streamed %d KB attachment", round($l/1024)), true);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("HandleGetAttachment(): attachment with %d KB sent to mobile", round($l/1024)));
}
catch (StatusException $s) {
// StatusException already logged so we just need to pass it upwards to send a HTTP error
......
......@@ -630,4 +630,19 @@ class Request {
return ($re) ? preg_replace($re, $replacevalue, $input) : '';
}
/**
* Returns base64 encoded "php://input"
* With POST request (our case), you can open and read
* multiple times "php://input"
*
* @access public
* @return string - base64 encoded wbxml
*/
public static function GetInputAsBase64() {
$input = fopen('php://input', 'r');
$wbxml = base64_encode(stream_get_contents($input));
fclose($input);
return $wbxml;
}
}
......@@ -129,17 +129,12 @@ abstract class RequestProcessor {
// if there is an error decoding wbxml, consume remaining data and include it in the WBXMLException
if (!$handler->Handle(Request::GetCommandCode())) {
$wbxmlLog = "no decoder";
if (self::$decoder) {
self::$decoder->readRemainingData();
$wbxmlLog = self::$decoder->getWBXMLLog();
}
throw new WBXMLException("Debug data: " . $wbxmlLog);
throw new WBXMLException("Debug data: " . Request::GetInputAsBase64());
}
// also log WBXML in happy case
if (self::$decoder && @constant('WBXML_DEBUG') === true) {
ZLog::Write(LOGLEVEL_WBXML, "WBXML-IN : ". self::$decoder->getWBXMLLog(), false);
if (@constant('WBXML_DEBUG') === true) {
ZLog::Write(LOGLEVEL_WBXML, "WBXML-IN : ". Request::GetInputAsBase64(), false);
}
}
......
......@@ -44,21 +44,13 @@
class WBXMLDecoder extends WBXMLDefs {
private $in;
private $inLog;
private $version;
private $publicid;
private $publicstringid;
private $charsetid;
private $stringtable;
private $inLog;
private $tagcp = 0;
private $attrcp = 0;
private $ungetbuffer;
private $log = false;
private $logStack = array();
private $inputBuffer = "";
private $isWBXML = true;
......@@ -105,31 +97,35 @@ class WBXMLDecoder extends WBXMLDefs {
/**
* WBXML Decode Constructor
* We only handle ActiveSync WBXML, which is a subset of WBXML
*
* @param stream $input the incoming data stream
*
* @access public
*/
public function WBXMLDecoder($input) {
// make sure WBXML_DEBUG is defined. It should be at this point
if (!defined('WBXML_DEBUG')) define('WBXML_DEBUG', false);
$this->log = defined('WBXML_DEBUG') && WBXML_DEBUG;
$this->in = $input;
$this->inLog = StringStreamWrapper::Open("");
$this->readVersion();
if (isset($this->version) && $this->version != self::VERSION) {
$version = $this->getByte();
if($version != self::VERSION) {
$this->inputBuffer .= chr($version);
$this->isWBXML = false;
return;
}
$this->publicid = $this->getMBUInt();
if($this->publicid == 0) {
$this->publicstringid = $this->getMBUInt();
}
$publicid = $this->getMBUInt();
if($publicid !== 1)
throw new WBXMLException("Wrong publicid : ".$publicid);
$this->charsetid = $this->getMBUInt();
$this->stringtable = $this->getStringTable();
$charsetid = $this->getMBUInt();
if ($charsetid !== 106)
throw new WBXMLException("Wrong charset : ".$charsetid);
$stringtablesize = $this->getMBUInt();
if ($stringtablesize !== 0)
throw new WBXMLException("Wrong string table size : ".$stringtablesize);
}
/**
......@@ -265,11 +261,7 @@ class WBXMLDecoder extends WBXMLDefs {
* @return string
*/
public function GetPlainInputStream() {
$plain = $this->inputBuffer;
while($data = fread($this->in, 4096))
$plain .= $data;
return $plain;
return $this->inputBuffer.stream_get_contents($this->in);
}
/**
......@@ -293,20 +285,6 @@ class WBXMLDecoder extends WBXMLDefs {
while($this->getElement());
}
/**
* Returns the WBXML data read from the stream
*
* @access public
* @return string - base64 encoded wbxml
*/
public function getWBXMLLog() {
$out = "";
if ($this->inLog) {
$out = base64_encode(stream_get_contents($this->inLog, -1,0));
}
return $out;
}
/**----------------------------------------------------------------------------------------------------------
* Private WBXMLDecoder stuff
*/
......@@ -326,6 +304,7 @@ class WBXMLDecoder extends WBXMLDefs {
}
$el = $this->_getToken();
if($this->log)
$this->logToken($el);
return $el;
......@@ -340,9 +319,6 @@ class WBXMLDecoder extends WBXMLDefs {
* @return
*/
private function logToken($el) {
if(!WBXML_DEBUG)
return;
$spaces = str_repeat(" ", count($this->logStack));
switch($el[EN_TYPE]) {
......@@ -376,217 +352,60 @@ class WBXMLDecoder extends WBXMLDefs {
WBXMLDecoder::ResetInWhile("decoderGetToken");
while(WBXMLDecoder::InWhile("decoderGetToken")) {
$byte = $this->getByte();
if(!isset($byte))
$byte = fread($this->in, 1);
if($byte === "" || $byte === false)
break;
$byte = ord($byte);
switch($byte) {
case WBXML_SWITCH_PAGE:
case self::WBXML_SWITCH_PAGE:
$this->tagcp = $this->getByte();
break;
case WBXML_END:
case self::WBXML_END:
$element[EN_TYPE] = EN_TYPE_ENDTAG;
return $element;
case WBXML_ENTITY:
$entity = $this->getMBUInt();
$element[EN_TYPE] = EN_TYPE_CONTENT;
$element[EN_CONTENT] = $this->entityToCharset($entity);
return $element;
case WBXML_STR_I:
case self::WBXML_STR_I:
$element[EN_TYPE] = EN_TYPE_CONTENT;
$element[EN_CONTENT] = $this->getTermStr();
return $element;
case WBXML_LITERAL:
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt());
$element[EN_FLAGS] = 0;
return $element;
case WBXML_EXT_I_0:
case WBXML_EXT_I_1:
case WBXML_EXT_I_2:
$this->getTermStr();
// Ignore extensions
continue;
case WBXML_PI:
// Ignore PI
$this->getAttributes();
continue;
case WBXML_LITERAL_C:
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt());
$element[EN_FLAGS] = EN_FLAGS_CONTENT;
return $element;
case WBXML_EXT_T_0:
case WBXML_EXT_T_1:
case WBXML_EXT_T_2:
$this->getMBUInt();
// Ingore extensions;
continue;
case WBXML_STR_T:
$element[EN_TYPE] = EN_TYPE_CONTENT;
$element[EN_CONTENT] = $this->getStringTableEntry($this->getMBUInt());
return $element;
case WBXML_LITERAL_A:
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt());
$element[EN_ATTRIBUTES] = $this->getAttributes();
$element[EN_FLAGS] = EN_FLAGS_ATTRIBUTES;
return $element;
case WBXML_EXT_0:
case WBXML_EXT_1:
case WBXML_EXT_2:
continue;
case WBXML_OPAQUE:
case self::WBXML_OPAQUE:
$length = $this->getMBUInt();
$element[EN_TYPE] = EN_TYPE_CONTENT;
$element[EN_CONTENT] = $this->getOpaque($length);
return $element;
case WBXML_LITERAL_AC:
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt());
$element[EN_ATTRIBUTES] = $this->getAttributes();
$element[EN_FLAGS] = EN_FLAGS_ATTRIBUTES | EN_FLAGS_CONTENT;
return $element;
case self::WBXML_ENTITY:
case self::WBXML_LITERAL:
case self::WBXML_EXT_I_0:
case self::WBXML_EXT_I_1:
case self::WBXML_EXT_I_2:
case self::WBXML_PI:
case self::WBXML_LITERAL_C:
case self::WBXML_EXT_T_0:
case self::WBXML_EXT_T_1:
case self::WBXML_EXT_T_2:
case self::WBXML_STR_T:
case self::WBXML_LITERAL_A:
case self::WBXML_EXT_0:
case self::WBXML_EXT_1:
case self::WBXML_EXT_2:
case self::WBXML_LITERAL_AC:
throw new WBXMLException("Invalid token :".$byte);
default:
if($byte & self::WBXML_WITH_ATTRIBUTES)
throw new WBXMLException("Attributes are not allowed :".$byte);
$element[EN_TYPE] = EN_TYPE_STARTTAG;
$element[EN_TAG] = $this->getMapping($this->tagcp, $byte & 0x3f);
$element[EN_FLAGS] = ($byte & 0x80 ? EN_FLAGS_ATTRIBUTES : 0) | ($byte & 0x40 ? EN_FLAGS_CONTENT : 0);
if($byte & 0x80)
$element[EN_ATTRIBUTES] = $this->getAttributes();
$element[EN_FLAGS] = ($byte & self::WBXML_WITH_CONTENT ? EN_FLAGS_CONTENT : 0);
return $element;
}
}
}
/**
* Gets attributes
*
* @access private
* @return
*/
private function getAttributes() {
$attributes = array();
$attr = "";
WBXMLDecoder::ResetInWhile("decoderGetAttributes");
while(WBXMLDecoder::InWhile("decoderGetAttributes")) {
$byte = $this->getByte();
if(count($byte) == 0)
break;
switch($byte) {
case WBXML_SWITCH_PAGE:
$this->attrcp = $this->getByte();
break;
case WBXML_END:
if($attr != "")
$attributes += $this->splitAttribute($attr);
return $attributes;
case WBXML_ENTITY:
$entity = $this->getMBUInt();
$attr .= $this->entityToCharset($entity);
return $attr; /* fmbiete's contribution r1534, ZP-324 */
case WBXML_STR_I:
$attr .= $this->getTermStr();
return $attr; /* fmbiete's contribution r1534, ZP-324 */
case WBXML_LITERAL:
if($attr != "")
$attributes += $this->splitAttribute($attr);
$attr = $this->getStringTableEntry($this->getMBUInt());
return $attr; /* fmbiete's contribution r1534, ZP-324 */
case WBXML_EXT_I_0:
case WBXML_EXT_I_1:
case WBXML_EXT_I_2:
$this->getTermStr();
continue;
case WBXML_PI:
case WBXML_LITERAL_C:
// Invalid
return false;
case WBXML_EXT_T_0:
case WBXML_EXT_T_1:
case WBXML_EXT_T_2:
$this->getMBUInt();
continue;
case WBXML_STR_T:
$attr .= $this->getStringTableEntry($this->getMBUInt());
return $attr; /* fmbiete's contribution r1534, ZP-324 */
case WBXML_LITERAL_A:
return false;
case WBXML_EXT_0:
case WBXML_EXT_1:
case WBXML_EXT_2:
continue;
case WBXML_OPAQUE:
$length = $this->getMBUInt();
$attr .= $this->getOpaque($length);
return $attr; /* fmbiete's contribution r1534, ZP-324 */
case WBXML_LITERAL_AC:
return false;
default:
if($byte < 128) {
if($attr != "") {
$attributes += $this->splitAttribute($attr);
$attr = "";
}
}
$attr .= $this->getMapping($this->attrcp, $byte);
break;
}
}
}
/**
* Splits an attribute
*
* @param string $attr attribute to be splitted
*
* @access private
* @return array
*/
private function splitAttribute($attr) {
$attributes = array();
$pos = strpos($attr,chr(61)); // equals sign
if($pos)
$attributes[substr($attr, 0, $pos)] = substr($attr, $pos+1);
else
$attributes[$attr] = null;
return $attributes;
}
/**
* Reads from the stream until getting a string terminator
*
......@@ -594,17 +413,12 @@ class WBXMLDecoder extends WBXMLDefs {
* @return string
*/
private function getTermStr() {
$str = "";
while(1) {
$in = $this->getByte();
if($in == 0)
break;
else
$str .= chr($in);
}
return $str;
// there is no unlimited "length" for stream_get_line,
// so we use a huge value for "length" param (1Gb)
// (0 == PHP_SOCK_CHUNK_SIZE (8192))
// internaly php read at most PHP_SOCK_CHUNK_SIZE at a time,
// so we can use a huge value for "length" without problem
return stream_get_line($this->in, 1073741824, "\0");
}
/**
......@@ -616,32 +430,12 @@ class WBXMLDecoder extends WBXMLDefs {
* @return string
*/
private function getOpaque($len) {
// TODO check if it's possible to do it other way
// fread stops reading because the following condition is true (from php.net):
// if the stream is read buffered and it does not represent a plain file,
// at most one read of up to a number of bytes equal to the chunk size
// (usually 8192) is made; depending on the previously buffered data,
// the size of the returned data may be larger than the chunk size.
// using only return fread it will return only a part of stream if chunk is smaller
// than $len. Read from stream in a loop until the $len is reached.
$d = "";
$l = 0;
while (1) {
$l = (($len - strlen($d)) > 8192) ? 8192 : ($len - strlen($d));
if ($l > 0) {
$data = fread($this->in, $l);
// Stream ends prematurely on instable connections and big mails
if ($data === false || feof($this->in))
throw new HTTPReturnCodeException(sprintf("WBXMLDecoder->getOpaque() connection unavailable while trying to read %d bytes from stream. Aborting after %d bytes read.", $len, strlen($d)), HTTP_CODE_500, null, LOGLEVEL_WARN);
else {
$d .= $data;
fwrite($this->inLog, $data);
}
}
if (strlen($d) >= $len) break;
}
$d = stream_get_contents($this->in, $len);
if ($d === false)
throw new HTTPReturnCodeException("WBXMLDecoder->getOpaque(): stream_get_contents === false", HTTP_CODE_500, null, LOGLEVEL_WARN);
$l = strlen($d);
if ($l !== $len)
throw new HTTPReturnCodeException("WBXMLDecoder->getOpaque(): only $l byte read instead of $len", HTTP_CODE_500, null, LOGLEVEL_WARN);
return $d;
}
......@@ -653,10 +447,8 @@ class WBXMLDecoder extends WBXMLDefs {
*/
private function getByte() {
$ch = fread($this->in, 1);
if(strlen($ch) > 0) {
fwrite($this->inLog, $ch);
if(strlen($ch) > 0)
return ord($ch);
}
else
return;
}
......@@ -684,24 +476,6 @@ class WBXMLDecoder extends WBXMLDefs {
return $uint;
}
/**
* Reads string table from the input stream
*
* @access private
* @return int
*/
private function getStringTable() {
$stringtable = "";
$length = $this->getMBUInt();
if($length > 0) {
$stringtable = fread($this->in, $length);
fwrite($this->inLog, $stringtable);
}
return $stringtable;
}
/**
* Returns the mapping for a specified codepage and id
*
......@@ -721,19 +495,4 @@ class WBXMLDecoder extends WBXMLDefs {
return $this->dtd["codes"][$cp][$id];
}
}
/**
* Reads one byte from the input stream
*
* @access private
* @return void
*/
private function readVersion() {
$ch = $this->getByte();
if($ch != NULL) {
$this->inputBuffer .= chr($ch);
$this->version = $ch;
}
}
}
......@@ -42,26 +42,7 @@
************************************************/
define('WBXML_SWITCH_PAGE', 0x00);
define('WBXML_END', 0x01);
define('WBXML_ENTITY', 0x02);
define('WBXML_STR_I', 0x03);
define('WBXML_LITERAL', 0x04);
define('WBXML_EXT_I_0', 0x40);
define('WBXML_EXT_I_1', 0x41);
define('WBXML_EXT_I_2', 0x42);
define('WBXML_PI', 0x43);
define('WBXML_LITERAL_C', 0x44);
define('WBXML_EXT_T_0', 0x80);
define('WBXML_EXT_T_1', 0x81);
define('WBXML_EXT_T_2', 0x82);
define('WBXML_STR_T', 0x83);
define('WBXML_LITERAL_A', 0x84);
define('WBXML_EXT_0', 0xC0);
define('WBXML_EXT_1', 0xC1);
define('WBXML_EXT_2', 0xC2);
define('WBXML_OPAQUE', 0xC3);
define('WBXML_LITERAL_AC', 0xC4);
define('EN_TYPE', 1);
define('EN_TAG', 2);
......@@ -77,6 +58,31 @@ define('EN_FLAGS_CONTENT', 1);
define('EN_FLAGS_ATTRIBUTES', 2);
class WBXMLDefs {
const WBXML_SWITCH_PAGE = 0x00;
const WBXML_END = 0x01;
const WBXML_ENTITY = 0x02; //not used in ActiveSync
const WBXML_STR_I = 0x03;
const WBXML_LITERAL = 0x04; //not used in ActiveSync
const WBXML_EXT_I_0 = 0x40; //not used in ActiveSync
const WBXML_EXT_I_1 = 0x41; //not used in ActiveSync
const WBXML_EXT_I_2 = 0x42; //not used in ActiveSync
const WBXML_PI = 0x43; //not used in ActiveSync
const WBXML_LITERAL_C = 0x44; //not used in ActiveSync
const WBXML_EXT_T_0 = 0x80; //not used in ActiveSync
const WBXML_EXT_T_1 = 0x81; //not used in ActiveSync
const WBXML_EXT_T_2 = 0x82; //not used in ActiveSync
const WBXML_STR_T = 0x83; //not used in ActiveSync
const WBXML_LITERAL_A = 0x84; //not used in ActiveSync
const WBXML_EXT_0 = 0xC0; //not used in ActiveSync
const WBXML_EXT_1 = 0xC1; //not used in ActiveSync
const WBXML_EXT_2 = 0xC2; //not used in ActiveSync
const WBXML_OPAQUE = 0xC3;
const WBXML_LITERAL_AC = 0xC4; //not used in ActiveSync
const WBXML_WITH_ATTRIBUTES = 0x80; //not used in ActiveSync
const WBXML_WITH_CONTENT = 0x40;
/**
* The WBXML DTDs
*/
......
......@@ -45,11 +45,10 @@
class WBXMLEncoder extends WBXMLDefs {
private $_dtd;
private $_out;
private $_outLog;
private $_tagcp;
private $_attrcp;
private $_tagcp = 0;
private $log = false;
private $logStack = array();
// We use a delayed output mechanism in which we only output a tag when it actually has something
......@@ -64,14 +63,9 @@ class WBXMLEncoder extends WBXMLDefs {
private $bodyparts;
public function WBXMLEncoder($output, $multipart = false) {
// make sure WBXML_DEBUG is defined. It should be at this point
if (!defined('WBXML_DEBUG')) define('WBXML_DEBUG', false);
$this->log = @constant('WBXML_DEBUG') === true;
$this->_out = $output;
$this->_outLog = StringStreamWrapper::Open("");
$this->_tagcp = 0;
$this->_attrcp = 0;
// reverse-map the DTD
foreach($this->dtd["namespaces"] as $nsid => $nsname) {
......@@ -126,7 +120,6 @@ class WBXMLEncoder extends WBXMLDefs {
if(!$nocontent) {
$stackelem['tag'] = $tag;
$stackelem['attributes'] = $attributes;
$stackelem['nocontent'] = $nocontent;
$stackelem['sent'] = false;
......@@ -136,7 +129,7 @@ class WBXMLEncoder extends WBXMLDefs {
// output of an empty tag, and we therefore output the stack here
} else {
$this->_outputStack();
$this->_startTag($tag, $attributes, $nocontent);
$this->_startTag($tag, $nocontent);
}
}
......@@ -225,6 +218,8 @@ class WBXMLEncoder extends WBXMLDefs {
* @return void
*/
public function addBodypartStream($bp) {
if (!is_resource($bp))
throw new WBXMLException("WBXMLEncoder->addBodypartStream(): trying to add a ".gettype($bp)." instead of a stream");
if ($this->multipart)
$this->bodyparts[] = $bp;
}
......@@ -252,7 +247,7 @@ class WBXMLEncoder extends WBXMLDefs {
private function _outputStack() {
for($i=0;$i<count($this->_stack);$i++) {
if(!$this->_stack[$i]['sent']) {
$this->_startTag($this->_stack[$i]['tag'], $this->_stack[$i]['attributes'], $this->_stack[$i]['nocontent']);
$this->_startTag($this->_stack[$i]['tag'], $this->_stack[$i]['nocontent']);
$this->_stack[$i]['sent'] = true;
}
}
......@@ -264,8 +259,9 @@ class WBXMLEncoder extends WBXMLDefs {
* @access private
* @return
*/
private function _startTag($tag, $attributes = false, $nocontent = false) {
$this->logStartTag($tag, $attributes, $nocontent);
private function _startTag($tag, $nocontent = false) {
if ($this->log)
$this->logStartTag($tag, $nocontent);
$mapping = $this->getMapping($tag);
......@@ -278,17 +274,11 @@ class WBXMLEncoder extends WBXMLDefs {
}
$code = $mapping["code"];
if(isset($attributes) && is_array($attributes) && count($attributes) > 0) {
$code |= 0x80;
}
if(!isset($nocontent) || !$nocontent)
$code |= 0x40;
$this->outByte($code);
if($code & 0x80)
$this->outAttributes($attributes);
}
/**
......@@ -299,8 +289,9 @@ class WBXMLEncoder extends WBXMLDefs {
* @return
*/
private function _content($content) {
if ($this->log)
$this->logContent($content);
$this->outByte(WBXML_STR_I);
$this->outByte(self::WBXML_STR_I);
$this->outTermStr($content);
}
......@@ -314,7 +305,7 @@ class WBXMLEncoder extends WBXMLDefs {
*/
private function _contentStream($stream, $asBase64) {
// write full stream, including the finalizing terminator to the output stream (stuff outTermStr() would do)
$this->outByte(WBXML_STR_I);
$this->outByte(self::WBXML_STR_I);
fseek($stream, 0, SEEK_SET);
if ($asBase64) {
$out_filter = stream_filter_append($this->_out, 'convert.base64-encode');
......@@ -325,14 +316,11 @@ class WBXMLEncoder extends WBXMLDefs {
}
fwrite($this->_out, chr(0));
if ($this->log) {
// data is out, do some logging
$stat = fstat($stream);
$logContent = sprintf("<<< written %d of %d bytes of %s data >>>", $written, $stat['size'], $asBase64 ? "base64 encoded":"plain");
$this->logContent($logContent);
// write the meta data also to the _outLog stream, WBXML_STR_I was already written by outByte() above
fwrite($this->_outLog, $logContent);
fwrite($this->_outLog, chr(0));
$this->logContent(sprintf("<<< written %d of %d bytes of %s data >>>", $written, $stat['size'], $asBase64 ? "base64 encoded":"plain"));
}
}
/**
......@@ -342,8 +330,9 @@ class WBXMLEncoder extends WBXMLDefs {
* @return
*/
private function _endTag() {
if ($this->log)
$this->logEndTag();
$this->outByte(WBXML_END);
$this->outByte(self::WBXML_END);
}
/**
......@@ -356,7 +345,6 @@ class WBXMLEncoder extends WBXMLDefs {
*/
private function outByte($byte) {
fwrite($this->_out, chr($byte));
fwrite($this->_outLog, chr($byte));
}
/**
......@@ -391,28 +379,6 @@ class WBXMLEncoder extends WBXMLDefs {
private function outTermStr($content) {
fwrite($this->_out, $content);
fwrite($this->_out, chr(0));
// truncate data bigger than 10 KB on outLog
$l = strlen($content);
if ($l > 10240) {
$content = substr($content, 0, 5120) . sprintf("...<data with total %d bytes truncated>...", $l) . substr($content, -5120);
}
fwrite($this->_outLog, $content);
fwrite($this->_outLog, chr(0));
}
/**
* Output attributes
* We don't actually support this, because to do so, we would have
* to build a string table before sending the data (but we can't
* because we're streaming), so we'll just send an END, which just
* terminates the attribute list with 0 attributes.
*
* @access private
* @return
*/
private function outAttributes() {
$this->outByte(WBXML_END);
}
/**
......@@ -424,7 +390,7 @@ class WBXMLEncoder extends WBXMLDefs {
* @return
*/
private function outSwitchPage($page) {
$this->outByte(WBXML_SWITCH_PAGE);
$this->outByte(self::WBXML_SWITCH_PAGE);
$this->outByte($page);
}
......@@ -488,16 +454,12 @@ class WBXMLEncoder extends WBXMLDefs {
* Logs a StartTag to ZLog
*
* @param $tag
* @param $attr
* @param $nocontent
*
* @access private
* @return
*/
private function logStartTag($tag, $attr, $nocontent) {
if(!WBXML_DEBUG)
return;
private function logStartTag($tag, $nocontent) {
$spaces = str_repeat(" ", count($this->logStack));
if($nocontent)
ZLog::Write(LOGLEVEL_WBXML,"O " . $spaces . " <$tag/>");
......@@ -514,9 +476,6 @@ class WBXMLEncoder extends WBXMLDefs {
* @return
*/
private function logEndTag() {
if(!WBXML_DEBUG)
return;
$spaces = str_repeat(" ", count($this->logStack));
$tag = array_pop($this->logStack);
ZLog::Write(LOGLEVEL_WBXML,"O " . $spaces . "</$tag>");
......@@ -531,9 +490,6 @@ class WBXMLEncoder extends WBXMLDefs {
* @return
*/
private function logContent($content) {
if(!WBXML_DEBUG)
return;
$spaces = str_repeat(" ", count($this->logStack));
ZLog::Write(LOGLEVEL_WBXML,"O " . $spaces . $content);
}
......@@ -551,28 +507,20 @@ class WBXMLEncoder extends WBXMLDefs {
$nrBodyparts = $this->getBodypartsCount();
$blockstart = (($nrBodyparts + 1) * 2) * 4 + 4;
$data = pack("iii", ($nrBodyparts + 1), $blockstart, $len);
ob_start(null, 1048576);
fwrite($this->_out, pack("iii", ($nrBodyparts + 1), $blockstart, $len));
foreach ($this->bodyparts as $bp) {
$blockstart = $blockstart + $len;
$len = fstat($bp);
$len = (isset($len['size'])) ? $len['size'] : 0;
$data .= pack("ii", $blockstart, $len);
fwrite($this->_out, pack("ii", $blockstart, $len));
}
fwrite($this->_out, $data);
fwrite($this->_out, $buffer);
fwrite($this->_outLog, $data);
fwrite($this->_outLog, $buffer);
foreach($this->bodyparts as $bp) {
while (!feof($bp)) {
$out = fread($bp, 4096);
fwrite($this->_out, $out);
fwrite($this->_outLog, $out);
}
stream_copy_to_stream($bp, $this->_out);
fclose($bp);
}
}
......@@ -583,11 +531,11 @@ class WBXMLEncoder extends WBXMLDefs {
* @return void
*/
private function writeLog() {
$stat = fstat($this->_outLog);
if ($stat['size'] < 524288) {
$data = base64_encode(stream_get_contents($this->_outLog, -1,0));
}
else {
if (ob_get_length() === false) {
$data = "output buffer disabled";
} elseif (ob_get_length() < 524288) {
$data = base64_encode(ob_get_contents());
} else {
$data = "more than 512K of data";
}
ZLog::Write(LOGLEVEL_WBXML, "WBXML-OUT: ". $data, false);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment