Skip to content

Commit 64ba987

Browse files
author
Kent Richards
committed
Correct setting of server vars to recognize cli environment variables.
1 parent 4b61a9d commit 64ba987

File tree

1 file changed

+152
-137
lines changed

1 file changed

+152
-137
lines changed

Bridges/DrupalKernel.php

Lines changed: 152 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,155 +1,170 @@
11
<?php
22

3+
/**
4+
* @file
5+
* Contains \PHPPM\Bridges\DrupalKernel.
6+
*/
7+
38
namespace PHPPM\Bridges;
49

5-
use PHPPM\AppBootstrapInterface;
6-
use PHPPM\Bootstraps\BootstrapInterface;
710
use PHPPM\Bridges\BridgeInterface;
811
use PHPPM\Bridges\HttpKernel as SymfonyBridge;
912
use React\Http\Request as ReactRequest;
1013
use React\Http\Response as ReactResponse;
11-
use Stack\Builder;
1214
use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
1315
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
1416
use Symfony\Component\HttpFoundation\StreamedResponse as SymfonyStreamedResponse;
1517
use Symfony\Component\HttpKernel\TerminableInterface;
1618

1719

18-
class DrupalKernel extends SymfonyBridge implements BridgeInterface
19-
{
20-
21-
/**
22-
* Handle a request using a HttpKernelInterface implementing application.
23-
*
24-
* @param \React\Http\Request $request
25-
* @param \React\Http\Response $response
26-
*/
27-
public function onRequest(ReactRequest $request, ReactResponse $response)
28-
{
29-
if (null === $this->application) {
30-
return;
31-
}
32-
33-
$content = '';
34-
$headers = $request->getHeaders();
35-
$contentLength = isset($headers['Content-Length']) ? (int) $headers['Content-Length'] : 0;
36-
37-
$request->on('data', function($data)
38-
use ($request, $response, &$content, $contentLength)
39-
{
40-
// read data (may be empty for GET request)
41-
$content .= $data;
42-
43-
// handle request after receive
44-
if (strlen($content) >= $contentLength) {
45-
$syRequest = self::mapRequest($request, $content);
46-
47-
try {
48-
$syResponse = $this->application->handle($syRequest);
49-
} catch (\Exception $exception) {
50-
$response->writeHead(500); // internal server error
51-
$response->end();
52-
return;
53-
}
54-
55-
self::mapResponse($response, $syResponse);
56-
57-
if ($this->application instanceof TerminableInterface) {
58-
$this->application->terminate($syRequest, $syResponse);
59-
}
60-
}
61-
});
62-
}
63-
64-
/**
65-
* Convert React\Http\Request to Symfony\Component\HttpFoundation\Request
66-
*
67-
* @param ReactRequest $reactRequest
68-
* @return SymfonyRequest $syRequest
69-
*/
70-
protected static function mapRequest(ReactRequest $reactRequest, $content)
71-
{
72-
$method = $reactRequest->getMethod();
73-
$headers = $reactRequest->getHeaders();
74-
$query = $reactRequest->getQuery();
75-
$post = array();
76-
77-
// parse body?
78-
if (isset($headers['Content-Type']) && (0 === strpos($headers['Content-Type'], 'application/x-www-form-urlencoded'))
79-
&& in_array(strtoupper($method), array('POST', 'PUT', 'DELETE', 'PATCH'))
80-
) {
81-
parse_str($content, $post);
82-
}
83-
84-
$cookies = array();
85-
if (isset($headers['Cookie'])) {
86-
$headersCookie = explode(';', $headers['Cookie']);
87-
foreach ($headersCookie as $cookie) {
88-
list($name, $value) = explode('=', trim($cookie));
89-
$cookies[$name] = $value;
20+
/**
21+
* PHP-PM bridge adapter for DrupalKernel.
22+
*
23+
* Extends `\PHPPM\Bridges\HttpKernel` to populate various request
24+
* meta-variables specified by CGI/1.1 (RFC 3875).
25+
*
26+
* @see http://www.faqs.org/rfcs/rfc3875.html
27+
* @see http://php.net/manual/en/reserved.variables.server.php
28+
*/
29+
class DrupalKernel extends SymfonyBridge implements BridgeInterface {
30+
31+
/**
32+
* Handle a request using a HttpKernelInterface implementing application.
33+
*
34+
* @param \React\Http\Request $request
35+
* @param \React\Http\Response $response
36+
*/
37+
public function onRequest(ReactRequest $request, ReactResponse $response)
38+
{
39+
if (null === $this->application) {
40+
return;
41+
}
42+
43+
$content = '';
44+
$headers = $request->getHeaders();
45+
$contentLength = isset($headers['Content-Length']) ? (int) $headers['Content-Length'] : 0;
46+
47+
$request->on('data', function($data)
48+
use ($request, $response, &$content, $contentLength)
49+
{
50+
// read data (may be empty for GET request)
51+
$content .= $data;
52+
53+
// handle request after receive
54+
if (strlen($content) >= $contentLength) {
55+
$syRequest = self::mapRequest($request, $content);
56+
57+
try {
58+
$syResponse = $this->application->handle($syRequest);
59+
} catch (\Exception $exception) {
60+
$response->writeHead(500); // internal server error
61+
$response->end();
62+
return;
63+
}
64+
65+
self::mapResponse($response, $syResponse);
66+
67+
if ($this->application instanceof TerminableInterface) {
68+
$this->application->terminate($syRequest, $syResponse);
69+
}
9070
}
71+
});
72+
}
73+
74+
/**
75+
* Convert React\Http\Request to Symfony\Component\HttpFoundation\Request
76+
*
77+
* @param ReactRequest $reactRequest
78+
* @return SymfonyRequest $syRequest
79+
*/
80+
protected static function mapRequest(ReactRequest $reactRequest, $content)
81+
{
82+
$method = $reactRequest->getMethod();
83+
$headers = $reactRequest->getHeaders();
84+
$query = $reactRequest->getQuery();
85+
$post = array();
86+
87+
// parse body?
88+
if (isset($headers['Content-Type']) && (0 === strpos($headers['Content-Type'], 'application/x-www-form-urlencoded'))
89+
&& in_array(strtoupper($method), array('POST', 'PUT', 'DELETE', 'PATCH'))
90+
) {
91+
parse_str($content, $post);
92+
}
93+
94+
$cookies = array();
95+
if (isset($headers['Cookie'])) {
96+
$headersCookie = explode(';', $headers['Cookie']);
97+
foreach ($headersCookie as $cookie) {
98+
list($name, $value) = explode('=', trim($cookie));
99+
$cookies[$name] = $value;
91100
}
92-
93-
$parameters =
94-
in_array(strtoupper($method), array('POST', 'PUT', 'DELETE', 'PATCH'))
95-
? $post
96-
: $query;
97-
$syRequest = SymfonyRequest::create(
98-
// $uri, $method, $parameters, $cookies, $files, $server, $content
99-
$reactRequest->getPath(),
100-
$method,
101-
$parameters,
102-
$cookies,
103-
array(),
104-
array(),
105-
$content
106-
);
107-
$syRequest->headers->replace($headers);
108-
109-
// Set CGI/1.1 (RFC 3875) server vars.
110-
// @see http://php.net/manual/en/reserved.variables.server.php
111-
// @see http://www.faqs.org/rfcs/rfc3875.html
112-
$serverVars = array_merge(
113-
$syRequest->server->all(),
114-
array(
115-
'DOCUMENT_ROOT' => $_SERVER['DOCUMENT_ROOT'],
116-
'GATEWAY_INTERFACE' => 'CGI/1.1',
117-
'SCRIPT_NAME' => $_SERVER['SCRIPT_NAME'],
118-
// SCRIPT_FILENAME contains the name of the php-pm startup script.
119-
// Must override here.
120-
'SCRIPT_FILENAME' => $_SERVER['DOCUMENT_ROOT'] . $_SERVER['SCRIPT_NAME'],
121-
)
122-
);
123-
$syRequest->server->replace($serverVars);
124-
125-
return $syRequest;
126-
}
127-
128-
129-
/**
130-
* Convert Symfony\Component\HttpFoundation\Response to React\Http\Response
131-
*
132-
* @param ReactResponse $reactResponse
133-
* @param SymfonyResponse $syResponse
134-
*/
135-
protected static function mapResponse(ReactResponse $reactResponse,
136-
SymfonyResponse $syResponse)
137-
{
138-
$headers = $syResponse->headers->all();
139-
$reactResponse->writeHead($syResponse->getStatusCode(), $headers);
140-
141-
// @TODO convert StreamedResponse in an async manner
142-
if ($syResponse instanceof SymfonyStreamedResponse) {
143-
ob_start();
144-
$syResponse->sendContent();
145-
$content = ob_get_contents();
146-
ob_end_clean();
147-
}
148-
else {
149-
$content = $syResponse->getContent();
150-
}
151-
152-
$reactResponse->end($content);
153-
}
101+
}
102+
103+
$parameters =
104+
in_array(strtoupper($method), array('POST', 'PUT', 'DELETE', 'PATCH'))
105+
? $post
106+
: $query;
107+
$syRequest = SymfonyRequest::create(
108+
// $uri, $method, $parameters, $cookies, $files, $server, $content
109+
$reactRequest->getPath(),
110+
$method,
111+
$parameters,
112+
$cookies,
113+
array(),
114+
array(),
115+
$content
116+
);
117+
$syRequest->headers->replace($headers);
118+
119+
// Set CGI/1.1 (RFC 3875) server vars.
120+
if (empty($_ENV)) {
121+
// In some cases with cli, $_ENV isn't set, so get with getenv().
122+
// @todo: Make this more efficient to eliminate running per request.
123+
// Static variable?
124+
$_ENV['DOCUMENT_ROOT'] = getenv('DOCUMENT_ROOT');
125+
$_ENV['SCRIPT_NAME'] = getenv('SCRIPT_NAME');
126+
}
127+
$serverVars = array_merge(
128+
$syRequest->server->all(),
129+
array(
130+
'DOCUMENT_ROOT' => $_ENV['DOCUMENT_ROOT'],
131+
'GATEWAY_INTERFACE' => 'CGI/1.1',
132+
'SCRIPT_NAME' => $_ENV['SCRIPT_NAME'],
133+
// SCRIPT_FILENAME contains the name of the php-pm startup script.
134+
// Must override here.
135+
'SCRIPT_FILENAME' => $_ENV['DOCUMENT_ROOT'] . $_ENV['SCRIPT_NAME'],
136+
)
137+
);
138+
$syRequest->server->replace($serverVars);
139+
140+
return $syRequest;
141+
}
142+
143+
144+
/**
145+
* Convert Symfony\Component\HttpFoundation\Response to React\Http\Response
146+
*
147+
* @param ReactResponse $reactResponse
148+
* @param SymfonyResponse $syResponse
149+
*/
150+
protected static function mapResponse(ReactResponse $reactResponse,
151+
SymfonyResponse $syResponse)
152+
{
153+
$headers = $syResponse->headers->all();
154+
$reactResponse->writeHead($syResponse->getStatusCode(), $headers);
155+
156+
// @TODO convert StreamedResponse in an async manner
157+
if ($syResponse instanceof SymfonyStreamedResponse) {
158+
ob_start();
159+
$syResponse->sendContent();
160+
$content = ob_get_contents();
161+
ob_end_clean();
162+
}
163+
else {
164+
$content = $syResponse->getContent();
165+
}
166+
167+
$reactResponse->end($content);
168+
}
154169

155170
}

0 commit comments

Comments
 (0)