mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-27 11:41:09 -04:00
424 lines
10 KiB
PHP
424 lines
10 KiB
PHP
<?php
|
|
|
|
namespace Crater\Proxy;
|
|
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Contracts\Container\Container;
|
|
use Illuminate\Contracts\Http\Kernel as HttpKernel;
|
|
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
|
|
use Symfony\Component\HttpFoundation\File\UploadedFile as SymfonyUploadedFile;
|
|
|
|
class HttpKernelProxy
|
|
{
|
|
/**
|
|
* Additional headers for the request.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $defaultHeaders = [];
|
|
|
|
/**
|
|
* Additional server variables for the request.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $serverVariables = [];
|
|
|
|
/**
|
|
* Indicates whether redirects should be followed.
|
|
*
|
|
* @var bool
|
|
*/
|
|
protected $followRedirects = false;
|
|
|
|
/**
|
|
* The constructor for the proxy.
|
|
*
|
|
* @param \Illuminate\Contracts\Container\Container $app
|
|
*/
|
|
public function __construct(Container $app)
|
|
{
|
|
$this->app = $app;
|
|
}
|
|
|
|
/**
|
|
* Define additional headers to be sent with the request.
|
|
*
|
|
* @param array $headers
|
|
* @return $this
|
|
*/
|
|
public function withHeaders(array $headers)
|
|
{
|
|
$this->defaultHeaders = array_merge($this->defaultHeaders, $headers);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add a header to be sent with the request.
|
|
*
|
|
* @param string $name
|
|
* @param string $value
|
|
* @return $this
|
|
*/
|
|
public function withHeader(string $name, string $value)
|
|
{
|
|
$this->defaultHeaders[$name] = $value;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Flush all the configured headers.
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function flushHeaders()
|
|
{
|
|
$this->defaultHeaders = [];
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Define a set of server variables to be sent with the requests.
|
|
*
|
|
* @param array $server
|
|
* @return $this
|
|
*/
|
|
public function withServerVariables(array $server)
|
|
{
|
|
$this->serverVariables = $server;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Automatically follow any redirects returned from the response.
|
|
*
|
|
* @return $this
|
|
*/
|
|
public function followingRedirects()
|
|
{
|
|
$this->followRedirects = true;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set the referer header to simulate a previous request.
|
|
*
|
|
* @param string $url
|
|
* @return $this
|
|
*/
|
|
public function from(string $url)
|
|
{
|
|
return $this->withHeader('referer', $url);
|
|
}
|
|
|
|
/**
|
|
* Visit the given URI with a GET request.
|
|
*
|
|
* @param string $uri
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function get($uri, array $headers = [])
|
|
{
|
|
$server = $this->transformHeadersToServerVars($headers);
|
|
|
|
return $this->call('GET', $uri, [], [], [], $server);
|
|
}
|
|
|
|
/**
|
|
* Visit the given URI with a GET request, expecting a JSON response.
|
|
*
|
|
* @param string $uri
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function getJson($uri, array $headers = [])
|
|
{
|
|
return $this->json('GET', $uri, [], $headers);
|
|
}
|
|
|
|
/**
|
|
* Visit the given URI with a POST request.
|
|
*
|
|
* @param string $uri
|
|
* @param array $data
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function post($uri, array $data = [], array $headers = [])
|
|
{
|
|
$server = $this->transformHeadersToServerVars($headers);
|
|
|
|
return $this->call('POST', $uri, $data, [], [], $server);
|
|
}
|
|
|
|
/**
|
|
* Visit the given URI with a POST request, expecting a JSON response.
|
|
*
|
|
* @param string $uri
|
|
* @param array $data
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function postJson($uri, array $data = [], array $headers = [])
|
|
{
|
|
return $this->json('POST', $uri, $data, $headers);
|
|
}
|
|
|
|
/**
|
|
* Visit the given URI with a PUT request.
|
|
*
|
|
* @param string $uri
|
|
* @param array $data
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function put($uri, array $data = [], array $headers = [])
|
|
{
|
|
$server = $this->transformHeadersToServerVars($headers);
|
|
|
|
return $this->call('PUT', $uri, $data, [], [], $server);
|
|
}
|
|
|
|
/**
|
|
* Visit the given URI with a PUT request, expecting a JSON response.
|
|
*
|
|
* @param string $uri
|
|
* @param array $data
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function putJson($uri, array $data = [], array $headers = [])
|
|
{
|
|
return $this->json('PUT', $uri, $data, $headers);
|
|
}
|
|
|
|
/**
|
|
* Visit the given URI with a PATCH request.
|
|
*
|
|
* @param string $uri
|
|
* @param array $data
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function patch($uri, array $data = [], array $headers = [])
|
|
{
|
|
$server = $this->transformHeadersToServerVars($headers);
|
|
|
|
return $this->call('PATCH', $uri, $data, [], [], $server);
|
|
}
|
|
|
|
/**
|
|
* Visit the given URI with a PATCH request, expecting a JSON response.
|
|
*
|
|
* @param string $uri
|
|
* @param array $data
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function patchJson($uri, array $data = [], array $headers = [])
|
|
{
|
|
return $this->json('PATCH', $uri, $data, $headers);
|
|
}
|
|
|
|
/**
|
|
* Visit the given URI with a DELETE request.
|
|
*
|
|
* @param string $uri
|
|
* @param array $data
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function delete($uri, array $data = [], array $headers = [])
|
|
{
|
|
$server = $this->transformHeadersToServerVars($headers);
|
|
|
|
return $this->call('DELETE', $uri, $data, [], [], $server);
|
|
}
|
|
|
|
/**
|
|
* Visit the given URI with a DELETE request, expecting a JSON response.
|
|
*
|
|
* @param string $uri
|
|
* @param array $data
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function deleteJson($uri, array $data = [], array $headers = [])
|
|
{
|
|
return $this->json('DELETE', $uri, $data, $headers);
|
|
}
|
|
|
|
/**
|
|
* Call the given URI with a JSON request.
|
|
*
|
|
* @param string $method
|
|
* @param string $uri
|
|
* @param array $data
|
|
* @param array $headers
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function json($method, $uri, array $data = [], array $headers = [])
|
|
{
|
|
$files = $this->extractFilesFromDataArray($data);
|
|
|
|
$content = json_encode($data);
|
|
|
|
$headers = array_merge([
|
|
'CONTENT_LENGTH' => mb_strlen($content, '8bit'),
|
|
'CONTENT_TYPE' => 'application/json',
|
|
'Accept' => 'application/json',
|
|
], $headers);
|
|
|
|
return $this->call(
|
|
$method,
|
|
$uri,
|
|
[],
|
|
[],
|
|
$files,
|
|
$this->transformHeadersToServerVars($headers),
|
|
$content
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Call the given URI and return the Response.
|
|
*
|
|
* @param string $method
|
|
* @param string $uri
|
|
* @param array $parameters
|
|
* @param array $cookies
|
|
* @param array $files
|
|
* @param array $server
|
|
* @param string $content
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
|
|
{
|
|
$kernel = $this->app->make(HttpKernel::class);
|
|
|
|
$files = array_merge($files, $this->extractFilesFromDataArray($parameters));
|
|
|
|
$symfonyRequest = SymfonyRequest::create(
|
|
$this->prepareUrlForRequest($uri),
|
|
$method,
|
|
$parameters,
|
|
$cookies,
|
|
$files,
|
|
array_replace($this->serverVariables, $server),
|
|
$content
|
|
);
|
|
|
|
$response = $kernel->handle(
|
|
$request = Request::createFromBase($symfonyRequest)
|
|
);
|
|
|
|
if ($this->followRedirects) {
|
|
$response = $this->followRedirects($response);
|
|
}
|
|
|
|
$kernel->terminate($request, $response);
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* Turn the given URI into a fully qualified URL.
|
|
*
|
|
* @param string $uri
|
|
* @return string
|
|
*/
|
|
protected function prepareUrlForRequest($uri)
|
|
{
|
|
if (Str::startsWith($uri, '/')) {
|
|
$uri = substr($uri, 1);
|
|
}
|
|
|
|
if (!Str::startsWith($uri, 'http')) {
|
|
$uri = config('app.url') . '/' . $uri;
|
|
}
|
|
|
|
return trim($uri, '/');
|
|
}
|
|
|
|
/**
|
|
* Transform headers array to array of $_SERVER vars with HTTP_* format.
|
|
*
|
|
* @param array $headers
|
|
* @return array
|
|
*/
|
|
protected function transformHeadersToServerVars(array $headers)
|
|
{
|
|
return collect(array_merge($this->defaultHeaders, $headers))->mapWithKeys(function ($value, $name) {
|
|
$name = strtr(strtoupper($name), '-', '_');
|
|
|
|
return [$this->formatServerHeaderKey($name) => $value];
|
|
})->all();
|
|
}
|
|
|
|
/**
|
|
* Format the header name for the server array.
|
|
*
|
|
* @param string $name
|
|
* @return string
|
|
*/
|
|
protected function formatServerHeaderKey($name)
|
|
{
|
|
if (!Str::startsWith($name, 'HTTP_') && $name != 'CONTENT_TYPE' && $name != 'REMOTE_ADDR') {
|
|
return 'HTTP_' . $name;
|
|
}
|
|
|
|
return $name;
|
|
}
|
|
|
|
/**
|
|
* Extract the file uploads from the given data array.
|
|
*
|
|
* @param array $data
|
|
* @return array
|
|
*/
|
|
protected function extractFilesFromDataArray(&$data)
|
|
{
|
|
$files = [];
|
|
|
|
foreach ($data as $key => $value) {
|
|
if ($value instanceof SymfonyUploadedFile) {
|
|
$files[$key] = $value;
|
|
|
|
unset($data[$key]);
|
|
}
|
|
|
|
if (is_array($value)) {
|
|
$files[$key] = $this->extractFilesFromDataArray($value);
|
|
|
|
$data[$key] = $value;
|
|
}
|
|
}
|
|
|
|
return $files;
|
|
}
|
|
|
|
/**
|
|
* Follow a redirect chain until a non-redirect is received.
|
|
*
|
|
* @param \Illuminate\Http\Response $response
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
protected function followRedirects($response)
|
|
{
|
|
while ($response->isRedirect()) {
|
|
$response = $this->get($response->headers->get('Location'));
|
|
}
|
|
|
|
$this->followRedirects = false;
|
|
|
|
return $response;
|
|
}
|
|
}
|