Merge "Selenium: replace UserLoginPage with BlankPage where possible"
[lhc/web/wiklou.git] / includes / Rest / StringStream.php
1 <?php
2
3 namespace MediaWiki\Rest;
4
5 /**
6 * A stream class which uses a string as the underlying storage. Surprisingly,
7 * Guzzle does not appear to have one of these. BufferStream does not do what
8 * we want.
9 *
10 * The normal use of this class should be to first write to the stream, then
11 * rewind, then read back the whole buffer with getContents().
12 *
13 * Seeking is supported, however seeking past the end of the string does not
14 * fill with null bytes as in a real file, it throws an exception instead.
15 */
16 class StringStream implements CopyableStreamInterface {
17 private $contents = '';
18 private $offset = 0;
19
20 /**
21 * Construct a StringStream with the given contents.
22 *
23 * The offset will start at 0, ready for reading. If appending to the
24 * given string is desired, you should first seek to the end.
25 *
26 * @param string $contents
27 */
28 public function __construct( $contents = '' ) {
29 $this->contents = $contents;
30 }
31
32 public function copyToStream( $stream ) {
33 fwrite( $stream, $this->getContents() );
34 }
35
36 public function __toString() {
37 return $this->contents;
38 }
39
40 public function close() {
41 }
42
43 public function detach() {
44 return null;
45 }
46
47 public function getSize() {
48 return strlen( $this->contents );
49 }
50
51 public function tell() {
52 return $this->offset;
53 }
54
55 public function eof() {
56 return $this->offset >= strlen( $this->contents );
57 }
58
59 public function isSeekable() {
60 return true;
61 }
62
63 public function seek( $offset, $whence = SEEK_SET ) {
64 switch ( $whence ) {
65 case SEEK_SET:
66 $this->offset = $offset;
67 break;
68
69 case SEEK_CUR:
70 $this->offset += $offset;
71 break;
72
73 case SEEK_END:
74 $this->offset = strlen( $this->contents ) + $offset;
75 break;
76
77 default:
78 throw new \InvalidArgumentException( "Invalid value for \$whence" );
79 }
80 if ( $this->offset > strlen( $this->contents ) ) {
81 throw new \InvalidArgumentException( "Cannot seek beyond the end of a StringStream" );
82 }
83 if ( $this->offset < 0 ) {
84 throw new \InvalidArgumentException( "Cannot seek before the start of a StringStream" );
85 }
86 }
87
88 public function rewind() {
89 $this->offset = 0;
90 }
91
92 public function isWritable() {
93 return true;
94 }
95
96 public function write( $string ) {
97 if ( $this->offset === strlen( $this->contents ) ) {
98 $this->contents .= $string;
99 } else {
100 $this->contents = substr_replace( $this->contents, $string,
101 $this->offset, strlen( $string ) );
102 }
103 $this->offset += strlen( $string );
104 return strlen( $string );
105 }
106
107 public function isReadable() {
108 return true;
109 }
110
111 public function read( $length ) {
112 if ( $this->offset === 0 && $length >= strlen( $this->contents ) ) {
113 $ret = $this->contents;
114 } elseif ( $this->offset >= strlen( $this->contents ) ) {
115 $ret = '';
116 } else {
117 $ret = substr( $this->contents, $this->offset, $length );
118 }
119 $this->offset += strlen( $ret );
120 return $ret;
121 }
122
123 public function getContents() {
124 if ( $this->offset === 0 ) {
125 $ret = $this->contents;
126 } elseif ( $this->offset >= strlen( $this->contents ) ) {
127 $ret = '';
128 } else {
129 $ret = substr( $this->contents, $this->offset );
130 }
131 $this->offset = strlen( $this->contents );
132 return $ret;
133 }
134
135 public function getMetadata( $key = null ) {
136 return null;
137 }
138 }