mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-30 21:21: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;
 | |
|     }
 | |
| }
 |