mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-11-03 22:13:18 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			424 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			424 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace Laraspace\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;
 | 
						|
    }
 | 
						|
}
 |