1
|
|
|
<?php |
2
|
|
|
namespace WebStream\IO; |
3
|
|
|
|
4
|
|
|
use WebStream\Exception\Extend\IOException; |
5
|
|
|
use WebStream\Exception\Extend\InvalidArgumentException; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* InputStream |
9
|
|
|
* @author Ryuichi TANAKA. |
10
|
|
|
* @since 2016/02/05 |
11
|
|
|
* @version 0.7 |
12
|
|
|
*/ |
13
|
|
|
class InputStream |
14
|
|
|
{ |
15
|
|
|
/** |
16
|
|
|
* @var resource 入力ストリーム |
17
|
|
|
*/ |
18
|
|
|
protected $stream; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var int 現在のポインタ位置 |
22
|
|
|
*/ |
23
|
|
|
protected $cursorPosition; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var int markしたポインタ位置 |
27
|
|
|
*/ |
28
|
|
|
protected $markedPosition; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* constructor |
32
|
|
|
* @param resource $stream 入力ストリーム |
33
|
|
|
*/ |
34
|
|
|
public function __construct($stream) |
35
|
|
|
{ |
36
|
|
|
if (!is_resource($stream)) { |
37
|
|
|
throw new IOException("Input stream must be type of Resource."); |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
$this->stream = $stream; |
41
|
|
|
$this->cursorPosition = 0; |
42
|
|
|
$this->markedPosition = 0; |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* destructor |
47
|
|
|
*/ |
48
|
|
|
public function __destruct() |
49
|
|
|
{ |
50
|
|
|
$this->close(); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* 入力ストリームを閉じる |
55
|
|
|
*/ |
56
|
|
|
public function close() |
57
|
|
|
{ |
58
|
|
|
if ($this->stream === null) { |
59
|
|
|
return; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
View Code Duplication |
if (@flose($this->stream) === false) { |
|
|
|
|
63
|
|
|
throw new IOException("Cannot close " . $this->file->getAbsoluteFilePath() . " cause by " . $php_errormsg); |
|
|
|
|
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
$this->stream = null; |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* 入力ストリームからデータを読み込む |
71
|
|
|
* 引数に数値を指定した場合、指定数値バイトだけ読み込む |
72
|
|
|
* @param int length 読み込みバイト数 |
73
|
|
|
* @return string 読み込みデータ |
74
|
|
|
* @throws InvalidArgumentException |
75
|
|
|
*/ |
76
|
|
|
public function read($length = null) |
77
|
|
|
{ |
78
|
|
|
if ($this->eof()) { |
79
|
|
|
return -1; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
$out = ""; |
83
|
|
|
if ($length === null) { |
84
|
|
|
while (!$this->eof()) { |
85
|
|
|
// InputStreamでは固定値でしか読み込ませない |
86
|
|
|
$out .= fread($this->stream, 8192); |
87
|
|
|
$this->cursorPosition = ftell($this->stream); |
88
|
|
|
} |
89
|
|
|
} else { |
90
|
|
|
if (!is_int($length)) { |
91
|
|
|
throw new InvalidArgumentException("Stream read must be a numeric value."); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
// $lengthだけ指定して読み込む |
95
|
|
|
$out = fread($this->stream, $length); |
96
|
|
|
$this->cursorPosition = ftell($this->stream); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
return $out; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* 入力ストリームから指定バイト数後方へポインタを移動する |
104
|
|
|
* @param int $pos 後方への移動バイト数(負数の場合は前方へ移動) |
105
|
|
|
* @return int $skipNum 移動したバイト数、移動に失敗した場合-1 |
106
|
|
|
*/ |
107
|
|
|
public function skip(int $pos) |
108
|
|
|
{ |
109
|
|
|
// 現在のポインタ位置から$posだけ後方へ移動 |
110
|
|
|
// シークに対応していないファイルシステムの場合、-1を返す |
111
|
|
|
if (fseek($this->stream, $pos, SEEK_CUR) === -1) { |
112
|
|
|
return -1; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
$start = $this->cursorPosition; |
116
|
|
|
$this->cursorPosition = ftell($this->stream); |
117
|
|
|
|
118
|
|
|
$skipNum = 0; |
|
|
|
|
119
|
|
View Code Duplication |
if ($start > $this->cursorPosition) { |
|
|
|
|
120
|
|
|
// 前方へ移動 |
121
|
|
|
$skipNum = $start - $this->cursorPosition; |
122
|
|
|
} else { |
123
|
|
|
// 後方へ移動 |
124
|
|
|
$skipNum = $this->cursorPosition - $start; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
return $skipNum; |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* 入力ストリームの現在位置にmarkを設定する |
132
|
|
|
* @throws IOException |
133
|
|
|
*/ |
134
|
|
|
public function mark() |
135
|
|
|
{ |
136
|
|
|
if (!$this->isMarkSupported()) { |
137
|
|
|
throw new IOException(get_class($this) . " does not support mark."); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
$this->markedPosition = $this->cursorPosition; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* 最後にmarkされた位置に再配置する |
145
|
|
|
* @throws IOException |
146
|
|
|
*/ |
147
|
|
|
public function reset() |
148
|
|
|
{ |
149
|
|
|
if (!$this->isMarkSupported()) { |
150
|
|
|
throw new IOException(get_class($this) . " does not support mark and reset."); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
// ポインタ位置をmark位置に移動 |
154
|
|
|
fseek($this->stream, SEEK_SET, $this->markedPosition); |
155
|
|
|
// mark位置を初期値に戻す |
156
|
|
|
$this->markedPosition = 0; |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* EOFかどうか返却する |
161
|
|
|
* @return bool EOFならtrue |
162
|
|
|
*/ |
163
|
|
|
public function eof() |
164
|
|
|
{ |
165
|
|
|
return feof($this->stream); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* mark機能をサポートしているかどうか |
170
|
|
|
* @return boolean マークをサポートしていればtrue |
171
|
|
|
*/ |
172
|
|
|
public function isMarkSupported() |
173
|
|
|
{ |
174
|
|
|
return false; |
175
|
|
|
} |
176
|
|
|
} |
177
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.