D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
psa
/
admin
/
plib
/
vendor
/
plesk
/
socket-client
/
src
/
Filename :
RequestWriter.php
back
Copy
<?php namespace Http\Client\Socket; use Http\Client\Socket\Exception\BrokenPipeException; use Psr\Http\Message\RequestInterface; /** * Method for writing request. * * Mainly used by SocketHttpClient * * @author Joel Wurtz <joel.wurtz@gmail.com> */ trait RequestWriter { /** * Write a request to a socket. * * @param resource $socket * * @return void * * @throws BrokenPipeException */ protected function writeRequest($socket, RequestInterface $request, int $bufferSize = 8192) { if (false === $this->fwrite($socket, $this->transformRequestHeadersToString($request))) { throw new BrokenPipeException('Failed to send request, underlying socket not accessible, (BROKEN EPIPE)', $request); } if ($request->getBody()->isReadable()) { $this->writeBody($socket, $request, $bufferSize); } } /** * Write Body of the request. * * @param resource $socket * * @return void * * @throws BrokenPipeException */ protected function writeBody($socket, RequestInterface $request, int $bufferSize = 8192) { $body = $request->getBody(); if ($body->isSeekable()) { $body->rewind(); } while (!$body->eof()) { $buffer = $body->read($bufferSize); if (false === $this->fwrite($socket, $buffer)) { throw new BrokenPipeException('An error occur when writing request to client (BROKEN EPIPE)', $request); } } } /** * Produce the header of request as a string based on a PSR Request. */ protected function transformRequestHeadersToString(RequestInterface $request): string { $message = vsprintf('%s %s HTTP/%s', [ strtoupper($request->getMethod()), $request->getRequestTarget(), $request->getProtocolVersion(), ])."\r\n"; foreach ($request->getHeaders() as $name => $values) { $message .= $name.': '.implode(', ', $values)."\r\n"; } $message .= "\r\n"; return $message; } /** * Replace fwrite behavior as api is broken in PHP. * * @see https://secure.phabricator.com/rPHU69490c53c9c2ef2002bc2dd4cecfe9a4b080b497 * * @param resource $stream The stream resource * * @return bool|int false if pipe is broken, number of bytes written otherwise */ private function fwrite($stream, string $bytes) { if (!strlen($bytes)) { return 0; } $result = @fwrite($stream, $bytes); if (0 !== $result) { // In cases where some bytes are witten (`$result > 0`) or // an error occurs (`$result === false`), the behavior of fwrite() is // correct. We can return the value as-is. return $result; } // If we make it here, we performed a 0-length write. Try to distinguish // between EAGAIN and EPIPE. To do this, we're going to `stream_select()` // the stream, write to it again if PHP claims that it's writable, and // consider the pipe broken if the write fails. $read = []; $write = [$stream]; $except = []; @stream_select($read, $write, $except, 0); if (!$write) { // The stream isn't writable, so we conclude that it probably really is // blocked and the underlying error was EAGAIN. Return 0 to indicate that // no data could be written yet. return 0; } // If we make it here, PHP **just** claimed that this stream is writable, so // perform a write. If the write also fails, conclude that these failures are // EPIPE or some other permanent failure. $result = @fwrite($stream, $bytes); if (0 !== $result) { // The write worked or failed explicitly. This value is fine to return. return $result; } // We performed a 0-length write, were told that the stream was writable, and // then immediately performed another 0-length write. Conclude that the pipe // is broken and return `false`. return false; } }