1<?php 2/*********************************************** 3* File : stringstreamwrapper.php 4* Project : Z-Push 5* Descr : Wraps a string as a standard php stream 6* The used method names are predefined and can not be altered. 7* 8* Created : 24.11.2011 9* 10* Copyright 2007 - 2013, 2015 - 2016 Zarafa Deutschland GmbH 11* 12* This program is free software: you can redistribute it and/or modify 13* it under the terms of the GNU Affero General Public License, version 3, 14* as published by the Free Software Foundation. 15* 16* This program is distributed in the hope that it will be useful, 17* but WITHOUT ANY WARRANTY; without even the implied warranty of 18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19* GNU Affero General Public License for more details. 20* 21* You should have received a copy of the GNU Affero General Public License 22* along with this program. If not, see <http://www.gnu.org/licenses/>. 23* 24* Consult LICENSE file for details 25************************************************/ 26 27class StringStreamWrapper { 28 const PROTOCOL = "stringstream"; 29 30 private $stringstream; 31 private $position; 32 private $stringlength; 33 private $truncateHtmlSafe; 34 35 /** 36 * Opens the stream 37 * The string to be streamed is passed over the context 38 * 39 * @param string $path Specifies the URL that was passed to the original function 40 * @param string $mode The mode used to open the file, as detailed for fopen() 41 * @param int $options Holds additional flags set by the streams API 42 * @param string $opened_path If the path is opened successfully, and STREAM_USE_PATH is set in options, 43 * opened_path should be set to the full path of the file/resource that was actually opened. 44 * 45 * @access public 46 * @return boolean 47 */ 48 public function stream_open($path, $mode, $options, &$opened_path) { 49 $contextOptions = stream_context_get_options($this->context); 50 if (!isset($contextOptions[self::PROTOCOL]['string'])) 51 return false; 52 53 $this->position = 0; 54 55 // this is our stream! 56 $this->stringstream = $contextOptions[self::PROTOCOL]['string']; 57 $this->truncateHtmlSafe = (isset($contextOptions[self::PROTOCOL]['truncatehtmlsafe'])) ? $contextOptions[self::PROTOCOL]['truncatehtmlsafe'] : false; 58 59 $this->stringlength = strlen($this->stringstream); 60 ZLog::Write(LOGLEVEL_DEBUG, sprintf("StringStreamWrapper::stream_open(): initialized stream length: %d - HTML-safe-truncate: %s", $this->stringlength, Utils::PrintAsString($this->truncateHtmlSafe))); 61 62 return true; 63 } 64 65 /** 66 * Reads from stream 67 * 68 * @param int $len amount of bytes to be read 69 * 70 * @access public 71 * @return string 72 */ 73 public function stream_read($len) { 74 $data = substr($this->stringstream, $this->position, $len); 75 $this->position += strlen($data); 76 return $data; 77 } 78 79 /** 80 * Writes data to the stream. 81 * 82 * @param string $data 83 * @return int 84 */ 85 public function stream_write($data){ 86 $l = strlen($data); 87 $this->stringstream = substr($this->stringstream, 0, $this->position) . $data . substr($this->stringstream, $this->position += $l); 88 $this->stringlength = strlen($this->stringstream); 89 return $l; 90 } 91 92 /** 93 * Stream "seek" functionality. 94 * 95 * @param int $offset 96 * @param int $whence 97 * @return boolean 98 */ 99 public function stream_seek($offset, $whence = SEEK_SET) { 100 if ($whence == SEEK_CUR) { 101 $this->position += $offset; 102 } 103 else if ($whence == SEEK_END) { 104 $this->position = $this->stringlength + $offset; 105 } 106 else { 107 $this->position = $offset; 108 } 109 return true; 110 } 111 112 /** 113 * Returns the current position on stream 114 * 115 * @access public 116 * @return int 117 */ 118 public function stream_tell() { 119 return $this->position; 120 } 121 122 /** 123 * Indicates if 'end of file' is reached 124 * 125 * @access public 126 * @return boolean 127 */ 128 public function stream_eof() { 129 return ($this->position >= $this->stringlength); 130 } 131 132 /** 133 * Truncates the stream to the new size. 134 * 135 * @param int $new_size 136 * @return boolean 137 */ 138 public function stream_truncate ($new_size) { 139 // cut the string! 140 $this->stringstream = Utils::Utf8_truncate($this->stringstream, $new_size, $this->truncateHtmlSafe); 141 $this->stringlength = strlen($this->stringstream); 142 143 if ($this->position > $this->stringlength) { 144 ZLog::Write(LOGLEVEL_WARN, sprintf("StringStreamWrapper->stream_truncate(): stream position (%d) ahead of new size of %d. Repositioning pointer to end of stream.", $this->position, $this->stringlength)); 145 $this->position = $this->stringlength; 146 } 147 return true; 148 } 149 150 /** 151 * Retrieves information about a stream 152 * 153 * @access public 154 * @return array 155 */ 156 public function stream_stat() { 157 return array( 158 7 => $this->stringlength, 159 'size' => $this->stringlength, 160 ); 161 } 162 163 /** 164 * Instantiates a StringStreamWrapper 165 * 166 * @param string $string The string to be wrapped 167 * @param boolean $truncatehtmlsafe Indicates if a truncation should be done html-safe - default: false 168 * 169 * @access public 170 * @return StringStreamWrapper 171 */ 172 static public function Open($string, $truncatehtmlsafe = false) { 173 $context = stream_context_create(array(self::PROTOCOL => array('string' => &$string, 'truncatehtmlsafe' => $truncatehtmlsafe))); 174 return fopen(self::PROTOCOL . "://",'r', false, $context); 175 } 176} 177 178stream_wrapper_register(StringStreamWrapper::PROTOCOL, "StringStreamWrapper"); 179