StringStreamWrapper   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 43
c 1
b 0
f 0
dl 0
loc 152
rs 10
wmc 13

9 Methods

Rating   Name   Duplication   Size   Complexity  
A stream_tell() 0 2 1
A stream_write() 0 6 1
A stream_seek() 0 12 3
A Open() 0 4 1
A stream_read() 0 5 1
A stream_stat() 0 4 1
A stream_eof() 0 2 1
A stream_truncate() 0 11 2
A stream_open() 0 16 2
1
<?php
2
3
/*
4
 * SPDX-License-Identifier: AGPL-3.0-only
5
 * SPDX-FileCopyrightText: Copyright 2007-2013,2015-2016 Zarafa Deutschland GmbH
6
 * SPDX-FileCopyrightText: Copyright 2020-2022 grommunio GmbH
7
 *
8
 * Wraps a string as a standard php stream
9
 * The used method names are predefined and can not be altered.
10
 */
11
12
class StringStreamWrapper {
13
	public const PROTOCOL = "stringstream";
14
15
	private $stringstream;
16
	private $position;
17
	private $stringlength;
18
	private $truncateHtmlSafe;
19
	private $context;
20
21
	/**
22
	 * Opens the stream
23
	 * The string to be streamed is passed over the context.
24
	 *
25
	 * @param string $path        Specifies the URL that was passed to the original function
26
	 * @param string $mode        The mode used to open the file, as detailed for fopen()
27
	 * @param int    $options     Holds additional flags set by the streams API
28
	 * @param string $opened_path if the path is opened successfully, and STREAM_USE_PATH is set in options,
29
	 *                            opened_path should be set to the full path of the file/resource that was actually opened
30
	 *
31
	 * @return bool
32
	 */
33
	public function stream_open($path, $mode, $options, &$opened_path) {
0 ignored issues
show
Unused Code introduced by
The parameter $path is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

33
	public function stream_open(/** @scrutinizer ignore-unused */ $path, $mode, $options, &$opened_path) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $opened_path is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

33
	public function stream_open($path, $mode, $options, /** @scrutinizer ignore-unused */ &$opened_path) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $mode is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

33
	public function stream_open($path, /** @scrutinizer ignore-unused */ $mode, $options, &$opened_path) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $options is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

33
	public function stream_open($path, $mode, /** @scrutinizer ignore-unused */ $options, &$opened_path) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
34
		$contextOptions = stream_context_get_options($this->context);
35
		if (!isset($contextOptions[self::PROTOCOL]['string'])) {
36
			return false;
37
		}
38
39
		$this->position = 0;
40
41
		// this is our stream!
42
		$this->stringstream = $contextOptions[self::PROTOCOL]['string'];
43
		$this->truncateHtmlSafe = $contextOptions[self::PROTOCOL]['truncatehtmlsafe'] ?? false;
44
45
		$this->stringlength = strlen($this->stringstream);
46
		SLog::Write(LOGLEVEL_DEBUG, sprintf("StringStreamWrapper::stream_open(): initialized stream length: %d - HTML-safe-truncate: %s", $this->stringlength, Utils::PrintAsString($this->truncateHtmlSafe)));
0 ignored issues
show
Bug introduced by
It seems like $this->truncateHtmlSafe can also be of type false; however, parameter $var of Utils::PrintAsString() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

46
		SLog::Write(LOGLEVEL_DEBUG, sprintf("StringStreamWrapper::stream_open(): initialized stream length: %d - HTML-safe-truncate: %s", $this->stringlength, Utils::PrintAsString(/** @scrutinizer ignore-type */ $this->truncateHtmlSafe)));
Loading history...
47
48
		return true;
49
	}
50
51
	/**
52
	 * Reads from stream.
53
	 *
54
	 * @param int $len amount of bytes to be read
55
	 *
56
	 * @return string
57
	 */
58
	public function stream_read($len) {
59
		$data = substr((string) $this->stringstream, $this->position, $len);
60
		$this->position += strlen($data);
61
62
		return $data;
63
	}
64
65
	/**
66
	 * Writes data to the stream.
67
	 *
68
	 * @param string $data
69
	 *
70
	 * @return int
71
	 */
72
	public function stream_write($data) {
73
		$l = strlen($data);
74
		$this->stringstream = substr((string) $this->stringstream, 0, $this->position) . $data . substr((string) $this->stringstream, $this->position += $l);
75
		$this->stringlength = strlen($this->stringstream);
76
77
		return $l;
78
	}
79
80
	/**
81
	 * Stream "seek" functionality.
82
	 *
83
	 * @param int $offset
84
	 * @param int $whence
85
	 *
86
	 * @return bool
87
	 */
88
	public function stream_seek($offset, $whence = SEEK_SET) {
89
		if ($whence == SEEK_CUR) {
90
			$this->position += $offset;
91
		}
92
		elseif ($whence == SEEK_END) {
93
			$this->position = $this->stringlength + $offset;
94
		}
95
		else {
96
			$this->position = $offset;
97
		}
98
99
		return true;
100
	}
101
102
	/**
103
	 * Returns the current position on stream.
104
	 *
105
	 * @return int
106
	 */
107
	public function stream_tell() {
108
		return $this->position;
109
	}
110
111
	/**
112
	 * Indicates if 'end of file' is reached.
113
	 *
114
	 * @return bool
115
	 */
116
	public function stream_eof() {
117
		return $this->position >= $this->stringlength;
118
	}
119
120
	/**
121
	 * Truncates the stream to the new size.
122
	 *
123
	 * @param int $new_size
124
	 *
125
	 * @return bool
126
	 */
127
	public function stream_truncate($new_size) {
128
		// cut the string!
129
		$this->stringstream = Utils::Utf8_truncate($this->stringstream, $new_size, $this->truncateHtmlSafe);
130
		$this->stringlength = strlen($this->stringstream);
131
132
		if ($this->position > $this->stringlength) {
133
			SLog::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));
134
			$this->position = $this->stringlength;
135
		}
136
137
		return true;
138
	}
139
140
	/**
141
	 * Retrieves information about a stream.
142
	 *
143
	 * @return array
144
	 */
145
	public function stream_stat() {
146
		return [
147
			7 => $this->stringlength,
148
			'size' => $this->stringlength,
149
		];
150
	}
151
152
	/**
153
	 * Instantiates a StringStreamWrapper.
154
	 *
155
	 * @param string $string           The string to be wrapped
156
	 * @param bool   $truncatehtmlsafe Indicates if a truncation should be done html-safe - default: false
157
	 *
158
	 * @return StringStreamWrapper
159
	 */
160
	public static function Open($string, $truncatehtmlsafe = false) {
161
		$context = stream_context_create([self::PROTOCOL => ['string' => &$string, 'truncatehtmlsafe' => $truncatehtmlsafe]]);
162
163
		return fopen(self::PROTOCOL . "://", 'r', false, $context);
0 ignored issues
show
Bug Best Practice introduced by
The expression return fopen(self::PROTO..., 'r', false, $context) returns the type resource which is incompatible with the documented return type StringStreamWrapper.
Loading history...
164
	}
165
}
166
167
stream_wrapper_register(StringStreamWrapper::PROTOCOL, "StringStreamWrapper");
168