Commit a883560a authored by Sebastian Kummer's avatar Sebastian Kummer

Merge pull request #562 in ZP/z-push from...

Merge pull request #562 in ZP/z-push from bugfix/ZP-1240-html-bodies-should-not-be-truncated to develop

* commit '4b293f5e':
  ZP-1240 Also HTML-trucate bodies from IMAP.
  ZP-1240 HTML safe truncate streams containing HTML data.
  ZP-1240 Add HTML safe truncation options to stream wrappers.
  ZP-1240 Add parameter $htmlsafe (default false) to Utils::Utf8_truncate().
parents 53ca2776 4b293f5e
...@@ -1124,7 +1124,8 @@ class BackendIMAP extends BackendDiff implements ISearchProvider { ...@@ -1124,7 +1124,8 @@ class BackendIMAP extends BackendDiff implements ISearchProvider {
} }
} }
$output->asbody->data = StringStreamWrapper::Open($data); // indicate in open that the data is HTML so it can be truncated correctly if required
$output->asbody->data = StringStreamWrapper::Open($data, ($bpReturnType == SYNC_BODYPREFERENCE_HTML));
$output->asbody->estimatedDataSize = strlen($data); $output->asbody->estimatedDataSize = strlen($data);
unset($data); unset($data);
$output->asbody->type = $bpReturnType; $output->asbody->type = $bpReturnType;
......
...@@ -2437,11 +2437,13 @@ class MAPIProvider { ...@@ -2437,11 +2437,13 @@ class MAPIProvider {
* @return boolean * @return boolean
*/ */
private function setMessageBodyForType($mapimessage, $bpReturnType, &$message) { private function setMessageBodyForType($mapimessage, $bpReturnType, &$message) {
$truncateHtmlSafe = false;
//default value is PR_BODY //default value is PR_BODY
$property = PR_BODY; $property = PR_BODY;
switch ($bpReturnType) { switch ($bpReturnType) {
case SYNC_BODYPREFERENCE_HTML: case SYNC_BODYPREFERENCE_HTML:
$property = PR_HTML; $property = PR_HTML;
$truncateHtmlSafe = true;
break; break;
case SYNC_BODYPREFERENCE_RTF: case SYNC_BODYPREFERENCE_RTF:
$property = PR_RTF_COMPRESSED; $property = PR_RTF_COMPRESSED;
...@@ -2473,11 +2475,11 @@ class MAPIProvider { ...@@ -2473,11 +2475,11 @@ class MAPIProvider {
elseif (isset($message->internetcpid) && $bpReturnType == SYNC_BODYPREFERENCE_HTML) { elseif (isset($message->internetcpid) && $bpReturnType == SYNC_BODYPREFERENCE_HTML) {
// if PR_HTML is UTF-8 we can stream it directly, else we have to convert to UTF-8 & wrap it // if PR_HTML is UTF-8 we can stream it directly, else we have to convert to UTF-8 & wrap it
if (Utils::GetCodepageCharset($message->internetcpid) == "utf-8") { if (Utils::GetCodepageCharset($message->internetcpid) == "utf-8") {
$message->asbody->data = MAPIStreamWrapper::Open($stream); $message->asbody->data = MAPIStreamWrapper::Open($stream, $truncateHtmlSafe);
} }
else { else {
$body = $this->mapiReadStream($stream, $streamsize); $body = $this->mapiReadStream($stream, $streamsize);
$message->asbody->data = StringStreamWrapper::Open(Utils::ConvertCodepageStringToUtf8($message->internetcpid, $body)); $message->asbody->data = StringStreamWrapper::Open(Utils::ConvertCodepageStringToUtf8($message->internetcpid, $body), $truncateHtmlSafe);
$message->internetcpid = INTERNET_CPID_UTF8; $message->internetcpid = INTERNET_CPID_UTF8;
} }
} }
......
...@@ -31,6 +31,7 @@ class MAPIStreamWrapper { ...@@ -31,6 +31,7 @@ class MAPIStreamWrapper {
private $position; private $position;
private $streamlength; private $streamlength;
private $toTruncate; private $toTruncate;
private $truncateHtmlSafe;
/** /**
* Opens the stream * Opens the stream
...@@ -52,6 +53,7 @@ class MAPIStreamWrapper { ...@@ -52,6 +53,7 @@ class MAPIStreamWrapper {
$this->position = 0; $this->position = 0;
$this->toTruncate = false; $this->toTruncate = false;
$this->truncateHtmlSafe = (isset($contextOptions[self::PROTOCOL]['truncatehtmlsafe'])) ? $contextOptions[self::PROTOCOL]['truncatehtmlsafe'] : false;
// this is our stream! // this is our stream!
$this->mapistream = $contextOptions[self::PROTOCOL]['stream']; $this->mapistream = $contextOptions[self::PROTOCOL]['stream'];
...@@ -65,7 +67,7 @@ class MAPIStreamWrapper { ...@@ -65,7 +67,7 @@ class MAPIStreamWrapper {
$this->streamlength = 0; $this->streamlength = 0;
} }
ZLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIStreamWrapper::stream_open(): initialized mapistream: %s streamlength: %d", $this->mapistream, $this->streamlength)); ZLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIStreamWrapper::stream_open(): initialized mapistream: %s - streamlength: %d - HTML-safe-truncate: %s", $this->mapistream, $this->streamlength, Utils::PrintAsString($this->truncateHtmlSafe)));
return true; return true;
} }
...@@ -95,7 +97,7 @@ class MAPIStreamWrapper { ...@@ -95,7 +97,7 @@ class MAPIStreamWrapper {
// we need to truncate UTF8 compatible if ftruncate() was called // we need to truncate UTF8 compatible if ftruncate() was called
if ($this->toTruncate && $this->position >= $this->streamlength) { if ($this->toTruncate && $this->position >= $this->streamlength) {
$data = Utils::Utf8_truncate($data, $this->streamlength); $data = Utils::Utf8_truncate($data, $this->streamlength, $this->truncateHtmlSafe);
} }
return $data; return $data;
...@@ -175,13 +177,14 @@ class MAPIStreamWrapper { ...@@ -175,13 +177,14 @@ class MAPIStreamWrapper {
/** /**
* Instantiates a MAPIStreamWrapper * Instantiates a MAPIStreamWrapper
* *
* @param mapistream $mapistream The stream to be wrapped * @param mapistream $mapistream The stream to be wrapped
* @param boolean $truncatehtmlsafe Indicates if a truncation should be done html-safe - default: false
* *
* @access public * @access public
* @return MAPIStreamWrapper * @return MAPIStreamWrapper
*/ */
static public function Open($mapistream) { static public function Open($mapistream, $truncatehtmlsafe = false) {
$context = stream_context_create(array(self::PROTOCOL => array('stream' => &$mapistream))); $context = stream_context_create(array(self::PROTOCOL => array('stream' => &$mapistream, 'truncatehtmlsafe' => $truncatehtmlsafe)));
return fopen(self::PROTOCOL . "://",'r', false, $context); return fopen(self::PROTOCOL . "://",'r', false, $context);
} }
} }
......
...@@ -30,6 +30,7 @@ class StringStreamWrapper { ...@@ -30,6 +30,7 @@ class StringStreamWrapper {
private $stringstream; private $stringstream;
private $position; private $position;
private $stringlength; private $stringlength;
private $truncateHtmlSafe;
/** /**
* Opens the stream * Opens the stream
...@@ -53,9 +54,10 @@ class StringStreamWrapper { ...@@ -53,9 +54,10 @@ class StringStreamWrapper {
// this is our stream! // this is our stream!
$this->stringstream = $contextOptions[self::PROTOCOL]['string']; $this->stringstream = $contextOptions[self::PROTOCOL]['string'];
$this->truncateHtmlSafe = (isset($contextOptions[self::PROTOCOL]['truncatehtmlsafe'])) ? $contextOptions[self::PROTOCOL]['truncatehtmlsafe'] : false;
$this->stringlength = strlen($this->stringstream); $this->stringlength = strlen($this->stringstream);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("StringStreamWrapper::stream_open(): initialized stream length: %d", $this->stringlength)); ZLog::Write(LOGLEVEL_DEBUG, sprintf("StringStreamWrapper::stream_open(): initialized stream length: %d - HTML-safe-truncate: %s", $this->stringlength, Utils::PrintAsString($this->truncateHtmlSafe)));
return true; return true;
} }
...@@ -135,7 +137,7 @@ class StringStreamWrapper { ...@@ -135,7 +137,7 @@ class StringStreamWrapper {
*/ */
public function stream_truncate ($new_size) { public function stream_truncate ($new_size) {
// cut the string! // cut the string!
$this->stringstream = Utils::Utf8_truncate($this->stringstream, $new_size); $this->stringstream = Utils::Utf8_truncate($this->stringstream, $new_size, $this->truncateHtmlSafe);
$this->stringlength = strlen($this->stringstream); $this->stringlength = strlen($this->stringstream);
if ($this->position > $this->stringlength) { if ($this->position > $this->stringlength) {
...@@ -161,13 +163,14 @@ class StringStreamWrapper { ...@@ -161,13 +163,14 @@ class StringStreamWrapper {
/** /**
* Instantiates a StringStreamWrapper * Instantiates a StringStreamWrapper
* *
* @param string $string The string to be wrapped * @param string $string The string to be wrapped
* @param boolean $truncatehtmlsafe Indicates if a truncation should be done html-safe - default: false
* *
* @access public * @access public
* @return StringStreamWrapper * @return StringStreamWrapper
*/ */
static public function Open($string) { static public function Open($string, $truncatehtmlsafe = false) {
$context = stream_context_create(array(self::PROTOCOL => array('string' => &$string))); $context = stream_context_create(array(self::PROTOCOL => array('string' => &$string, 'truncatehtmlsafe' => $truncatehtmlsafe)));
return fopen(self::PROTOCOL . "://",'r', false, $context); return fopen(self::PROTOCOL . "://",'r', false, $context);
} }
} }
......
...@@ -380,11 +380,13 @@ class Utils { ...@@ -380,11 +380,13 @@ class Utils {
* *
* If it's not possible to truncate properly, an empty string is returned * If it's not possible to truncate properly, an empty string is returned
* *
* @param string $string - the string * @param string $string the string
* @param string $length - position where string should be cut * @param string $length position where string should be cut
* @param boolean $htmlsafe doesn't cut html tags in half, doesn't ensure correct html - default: false
*
* @return string truncated string * @return string truncated string
*/ */
static public function Utf8_truncate($string, $length) { static public function Utf8_truncate($string, $length, $htmlsafe = false) {
// make sure length is always an interger // make sure length is always an interger
$length = (int)$length; $length = (int)$length;
...@@ -393,6 +395,16 @@ class Utils { ...@@ -393,6 +395,16 @@ class Utils {
$length = strlen($string) - 1; $length = strlen($string) - 1;
} }
// The intent is not to cut HTML tags in half which causes displaying issues (see ZP-1240).
// The used method just tries to cut outside of tags, without checking tag validity and closing tags.
if ($htmlsafe) {
$offset = 0 - strlen($string) + $length;
$validPos = strrpos($string, "<", $offset);
if ($validPos > strrpos($string, ">", $offset)) {
$length = $validPos;
}
}
while($length >= 0) { while($length >= 0) {
if ((ord($string[$length]) < 0x80) || (ord($string[$length]) >= 0xC0)) { if ((ord($string[$length]) < 0x80) || (ord($string[$length]) >= 0xC0)) {
return substr($string, 0, $length); return substr($string, 0, $length);
......
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