PluginProbe
The WP Remote WordPress Plugin / 6.65
The WP Remote WordPress Plugin v6.65
6.72 6.69 6.65 6.62 6.48 6.47 4.87 4.97 5.05 5.09 5.16 5.22 5.24 5.25 5.38 5.41 5.42 5.45 5.47 5.53 5.56 5.65 5.68 5.72 5.73 All 53 releases
wpremote / callback / streams.php

streams.php in The WP Remote WordPress Plugin 6.65, at callback/streams.php

260 lines 7.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fread
3 // phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
4 // phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fsockopen
5 // We use php method like fread, fwrite to read only a portion of a file, we don't have a direct method for partial reads since WP_Filesystem doesn't support a direct equivalent to fread, fwrite.
6 // The entire file deals with custom stream handling
7 // We need direct socket/file operations for this functionality
8 // WordPress filesystem alternatives wouldn't work for this use case
9 // It's better to disable these specific rules at file level than adding individual ignore comments
10 if (!defined('ABSPATH')) exit;
11 if (!class_exists('WPRRespStream')) :
12
13 class WPRStream extends WPRCallbackBase {
14 public $bvb64stream;
15 public $bvb64cksize;
16 public $checksum;
17
18 function __construct($request) {
19 $this->bvb64stream = $request->bvb64stream;
20 $this->bvb64cksize = $request->bvb64cksize;
21 $this->checksum = $request->checksum;
22 }
23
24 public function writeChunk($chunk) {
25 }
26
27 public static function startStream($account, $request) {
28 $result = array();
29 $params = $request->params;
30 $stream = new WPRRespStream($request);
31 if ($request->isAPICall()) {
32 $stream = new WPRHttpStream($request);
33 if (!$stream->connect()) {
34 $apicallstatus = array(
35 "httperror" => "Cannot Open Connection to Host",
36 "streamerrno" => $stream->errno,
37 "streamerrstr" => $stream->errstr
38 );
39 return array("apicallstatus" => $apicallstatus);
40 }
41 if (array_key_exists('acbmthd', $params)) {
42 $qstr = http_build_query(array('bvapicheck' => $params['bvapicheck']));
43 $url = '/bvapi/'.$params['acbmthd']."?".$qstr;
44 if (array_key_exists('acbqry', $params)) {
45 $url .= "&".$params['acbqry'];
46 }
47 $stream->multipartChunkedPost($url);
48 } else {
49 return array("apicallstatus" => array("httperror" => "ApiCall method not present"));
50 }
51 }
52 return array('stream' => $stream);
53 }
54
55 public function writeStream($chunk) {
56 if (strlen($chunk) > 0) {
57 $bvb64_prefix = "";
58 if ($this->bvb64stream) {
59 $chunk_size = $this->bvb64cksize;
60 $chunk = $this->base64Encode($chunk, $chunk_size);
61 $bvb64_prefix .= "BVB64" . ":";
62 }
63
64 $hash_prefix = "";
65 if ($this->checksum == 'crc32') {
66 $hash_prefix .= "CRC32" . ":" . crc32($chunk) . ":";
67 } else if ($this->checksum == 'md5') {
68 $hash_prefix .= "MD5" . ":" . md5($chunk) . ":";
69 }
70
71 $chunk = $hash_prefix . $bvb64_prefix . strlen($chunk) . ":" . $chunk;
72
73 $this->writeChunk($chunk);
74 }
75 }
76 }
77
78 class WPRRespStream extends WPRStream {
79 public $bvboundry;
80
81 function __construct($request) {
82 parent::__construct($request);
83 // Restrict boundary to safe chars so raw echo cannot inject into response (XSS).
84 $raw = isset($request->bvboundry) ? (string) $request->bvboundry : '';
85 $sanitized = preg_replace('/[^a-zA-Z0-9_-]/', '', $raw);
86 $this->bvboundry = $sanitized !== '' ? $sanitized : 'bvstream';
87 }
88
89 public function writeChunk($chunk) {
90 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- bvboundry sanitized in constructor; raw stream protocol (not HTML), chunk must not be escaped or stream is corrupted
91 echo $this->bvboundry . "ckckckckck" . $chunk . $this->bvboundry . "ckckckckck";
92 }
93 public function endStream() {
94 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- bvboundry sanitized in constructor; raw stream protocol (not HTML)
95 echo $this->bvboundry . "rerererere";
96
97 return array();
98 }
99 }
100
101 class WPRHttpStream extends WPRStream {
102 var $user_agent = 'WPRHttpStream';
103 var $host;
104 var $port;
105 var $timeout = 20;
106 var $conn;
107 var $errno;
108 var $errstr;
109 var $boundary;
110 var $apissl;
111
112 function __construct($request) {
113 parent::__construct($request);
114 $this->host = $request->params['apihost'];
115 $this->port = intval($request->params['apiport']);
116 $this->apissl = array_key_exists('apissl', $request->params);
117 }
118
119 public function connect() {
120 if ($this->apissl && function_exists('stream_socket_client')) {
121 $this->conn = stream_socket_client("ssl://".$this->host.":".$this->port, $errno, $errstr, $this->timeout);
122 } else {
123 $this->conn = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
124 }
125 if (!$this->conn) {
126 $this->errno = $errno;
127 $this->errstr = $errstr;
128 return false;
129 }
130 socket_set_timeout($this->conn, $this->timeout);
131 return true;
132 }
133
134 public function write($data) {
135 fwrite($this->conn, $data);
136 }
137
138 public function sendChunk($data) {
139 $this->write(sprintf("%x\r\n", strlen($data)));
140 $this->write($data);
141 $this->write("\r\n");
142 }
143
144 public function sendRequest($method, $url, $headers = array(), $body = null) {
145 $def_hdrs = array("Connection" => "keep-alive",
146 "Host" => $this->host);
147 $headers = array_merge($def_hdrs, $headers);
148 $request = strtoupper($method)." ".$url." HTTP/1.1\r\n";
149 if (null != $body) {
150 $headers["Content-length"] = strlen($body);
151 }
152 foreach($headers as $key=>$val) {
153 $request .= $key.":".$val."\r\n";
154 }
155 $request .= "\r\n";
156 if (null != $body) {
157 $request .= $body;
158 }
159 $this->write($request);
160 return $request;
161 }
162
163 public function post($url, $headers = array(), $body = "") {
164 if(is_array($body)) {
165 $b = "";
166 foreach($body as $key=>$val) {
167 $b .= $key."=".urlencode($val)."&";
168 }
169 $body = substr($b, 0, strlen($b) - 1);
170 }
171 $this->sendRequest("POST", $url, $headers, $body);
172 }
173
174 public function streamedPost($url, $headers = array()) {
175 $headers['Transfer-Encoding'] = "chunked";
176 $this->sendRequest("POST", $url, $headers);
177 }
178
179 public function multipartChunkedPost($url) {
180 $mph = array(
181 "Content-Disposition" => "form-data; name=bvinfile; filename=data",
182 "Content-Type" => "application/octet-stream"
183 );
184 $rnd = rand(100000, 999999); // phpcs:ignore WordPress.WP.AlternativeFunctions.rand_rand
185 $this->boundary = "----".$rnd;
186 $prologue = "--".$this->boundary."\r\n";
187 foreach($mph as $key=>$val) {
188 $prologue .= $key.":".$val."\r\n";
189 }
190 $prologue .= "\r\n";
191 $headers = array('Content-Type' => "multipart/form-data; boundary=".$this->boundary);
192 $this->streamedPost($url, $headers);
193 $this->sendChunk($prologue);
194 }
195
196 public function writeChunk($data) {
197 $this->sendChunk($data);
198 }
199
200 public function closeChunk() {
201 $this->sendChunk("");
202 }
203
204 public function endStream() {
205 $epilogue = "\r\n\r\n--".$this->boundary."--\r\n";
206 $this->sendChunk($epilogue);
207 $this->closeChunk();
208
209 $result = array();
210 $resp = $this->getResponse();
211 if (array_key_exists('httperror', $resp)) {
212 $result["httperror"] = $resp['httperror'];
213 } else {
214 $result["respstatus"] = $resp['status'];
215 $result["respstatus_string"] = $resp['status_string'];
216 }
217 return array("apicallstatus" => $result);
218 }
219
220 public function getResponse() {
221 $response = array();
222 $response['headers'] = array();
223 $state = 1;
224 $conlen = 0;
225 stream_set_timeout($this->conn, 300);
226 while (!feof($this->conn)) {
227 $line = fgets($this->conn, 4096);
228 if (1 == $state) {
229 if (!WPRHelper::safePregMatch('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/', $line, $m)) {
230 $response['httperror'] = "Status code line invalid: ".htmlentities($line);
231 return $response;
232 }
233 $response['http_version'] = $m[1];
234 $response['status'] = $m[2];
235 $response['status_string'] = $m[3];
236 $state = 2;
237 } else if (2 == $state) {
238 # End of headers
239 if (2 == strlen($line)) {
240 if ($conlen > 0)
241 $response['body'] = fread($this->conn, $conlen);
242 return $response;
243 }
244 if (!WPRHelper::safePregMatch('/([^:]+):\\s*(.*)/', $line, $m)) {
245 // Skip to the next header
246 continue;
247 }
248 $key = strtolower(trim($m[1]));
249 $val = trim($m[2]);
250 $response['headers'][$key] = $val;
251 if ($key == "content-length") {
252 $conlen = intval($val);
253 }
254 }
255 }
256 return $response;
257 }
258 }
259 // phpcs:enable
260 endif;