swooletw /
laravel-swoole
| 1 | <?php |
||
| 2 | |||
| 3 | namespace SwooleTW\Http\Transformers; |
||
| 4 | |||
| 5 | use Illuminate\Http\Response as IlluminateResponse; |
||
| 6 | use Swoole\Http\Response as SwooleResponse; |
||
| 7 | use Swoole\Http\Request as SwooleRequest; |
||
| 8 | use Symfony\Component\HttpFoundation\BinaryFileResponse; |
||
| 9 | use Symfony\Component\HttpFoundation\Response as SymfonyResponse; |
||
| 10 | use Symfony\Component\HttpFoundation\StreamedResponse; |
||
|
0 ignored issues
–
show
|
|||
| 11 | |||
| 12 | class Response |
||
| 13 | { |
||
| 14 | const CHUNK_SIZE = 8192; |
||
| 15 | |||
| 16 | /** |
||
| 17 | * @var \Swoole\Http\Response |
||
| 18 | */ |
||
| 19 | protected $swooleResponse; |
||
| 20 | |||
| 21 | /** |
||
| 22 | * @var \Swoole\Http\Request |
||
| 23 | */ |
||
| 24 | protected $swooleRequest; |
||
| 25 | |||
| 26 | /** |
||
| 27 | * @var \Illuminate\Http\Response |
||
| 28 | */ |
||
| 29 | protected $illuminateResponse; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * Make a response. |
||
| 33 | * |
||
| 34 | * @param $illuminateResponse |
||
| 35 | * @param \Swoole\Http\Response $swooleResponse |
||
| 36 | * @param \Swoole\Http\Request $swooleRequest |
||
| 37 | * |
||
| 38 | * @return \SwooleTW\Http\Transformers\Response |
||
| 39 | */ |
||
| 40 | public static function make($illuminateResponse, SwooleResponse $swooleResponse, SwooleRequest $swooleRequest) |
||
| 41 | { |
||
| 42 | return new static($illuminateResponse, $swooleResponse, $swooleRequest); |
||
| 43 | } |
||
| 44 | |||
| 45 | /** |
||
| 46 | * Response constructor. |
||
| 47 | * |
||
| 48 | * @param mixed $illuminateResponse |
||
| 49 | * @param \Swoole\Http\Response $swooleResponse |
||
| 50 | * @param \Swoole\Http\Request $swooleRequest |
||
| 51 | */ |
||
| 52 | public function __construct($illuminateResponse, SwooleResponse $swooleResponse, SwooleRequest $swooleRequest) |
||
| 53 | { |
||
| 54 | $this->setIlluminateResponse($illuminateResponse); |
||
| 55 | $this->setSwooleResponse($swooleResponse); |
||
| 56 | $this->setSwooleRequest($swooleRequest); |
||
| 57 | } |
||
| 58 | |||
| 59 | /** |
||
| 60 | * Send HTTP headers and content. |
||
| 61 | * |
||
| 62 | * @throws \InvalidArgumentException |
||
| 63 | */ |
||
| 64 | public function send() |
||
| 65 | { |
||
| 66 | $this->sendHeaders(); |
||
| 67 | $this->sendContent(); |
||
| 68 | } |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Send HTTP headers. |
||
| 72 | * |
||
| 73 | * @throws \InvalidArgumentException |
||
| 74 | */ |
||
| 75 | protected function sendHeaders() |
||
| 76 | { |
||
| 77 | $illuminateResponse = $this->getIlluminateResponse(); |
||
| 78 | |||
| 79 | /* RFC2616 - 14.18 says all Responses need to have a Date */ |
||
| 80 | if (! $illuminateResponse->headers->has('Date')) { |
||
| 81 | $illuminateResponse->setDate(\DateTime::createFromFormat('U', time())); |
||
| 82 | } |
||
| 83 | |||
| 84 | // headers |
||
| 85 | // allPreserveCaseWithoutCookies() doesn't exist before Laravel 5.3 |
||
| 86 | $headers = $illuminateResponse->headers->allPreserveCase(); |
||
| 87 | if (isset($headers['Set-Cookie'])) { |
||
| 88 | unset($headers['Set-Cookie']); |
||
| 89 | } |
||
| 90 | foreach ($headers as $name => $values) { |
||
| 91 | foreach ($values as $value) { |
||
| 92 | $this->swooleResponse->header($name, $value); |
||
| 93 | } |
||
| 94 | } |
||
| 95 | |||
| 96 | // status |
||
| 97 | $this->swooleResponse->status($illuminateResponse->getStatusCode()); |
||
| 98 | |||
| 99 | // cookies |
||
| 100 | // $cookie->isRaw() is supported after symfony/http-foundation 3.1 |
||
| 101 | // and Laravel 5.3, so we can add it back now |
||
| 102 | foreach ($illuminateResponse->headers->getCookies() as $cookie) { |
||
| 103 | $method = $cookie->isRaw() ? 'rawcookie' : 'cookie'; |
||
| 104 | $this->swooleResponse->$method( |
||
| 105 | $cookie->getName(), |
||
| 106 | $cookie->getValue(), |
||
| 107 | $cookie->getExpiresTime(), |
||
| 108 | $cookie->getPath(), |
||
| 109 | $cookie->getDomain(), |
||
| 110 | $cookie->isSecure(), |
||
| 111 | $cookie->isHttpOnly() |
||
| 112 | ); |
||
| 113 | } |
||
| 114 | } |
||
| 115 | |||
| 116 | /** |
||
| 117 | * Send HTTP content. |
||
| 118 | */ |
||
| 119 | protected function sendContent() |
||
| 120 | { |
||
| 121 | $illuminateResponse = $this->getIlluminateResponse(); |
||
| 122 | |||
| 123 | if ($illuminateResponse instanceof StreamedResponse && property_exists($illuminateResponse, 'output')) { |
||
|
0 ignored issues
–
show
|
|||
| 124 | // TODO Add Streamed Response with output |
||
| 125 | $this->swooleResponse->end($illuminateResponse->output); |
||
| 126 | } elseif ($illuminateResponse instanceof BinaryFileResponse) { |
||
|
0 ignored issues
–
show
|
|||
| 127 | $this->swooleResponse->sendfile($illuminateResponse->getFile()->getPathname()); |
||
| 128 | } else { |
||
| 129 | $chunkGzip = $this->canGzipContent($illuminateResponse->headers->get('Content-Encoding')); |
||
| 130 | $this->sendInChunk($illuminateResponse->getContent(), $chunkGzip); |
||
| 131 | } |
||
| 132 | } |
||
| 133 | |||
| 134 | /** |
||
| 135 | * Send content in chunk |
||
| 136 | * |
||
| 137 | * @param string $content |
||
| 138 | * @param bool $chunkGzip |
||
| 139 | */ |
||
| 140 | protected function sendInChunk($content, $chunkGzip) |
||
| 141 | { |
||
| 142 | if (strlen($content) <= static::CHUNK_SIZE) { |
||
| 143 | $this->swooleResponse->end($content); |
||
| 144 | return; |
||
| 145 | } |
||
| 146 | |||
| 147 | // Swoole Chunk mode does not support compress by default, this patch only supports gzip |
||
| 148 | if ($chunkGzip) { |
||
| 149 | $this->swooleResponse->header('Content-Encoding', 'gzip'); |
||
| 150 | $content = gzencode($content, config('swoole_http.server.options.http_compression_level', 3)); |
||
| 151 | } |
||
| 152 | |||
| 153 | foreach (str_split($content, static::CHUNK_SIZE) as $chunk) { |
||
| 154 | $this->swooleResponse->write($chunk); |
||
| 155 | } |
||
| 156 | |||
| 157 | $this->swooleResponse->end(); |
||
| 158 | } |
||
| 159 | |||
| 160 | /** |
||
| 161 | * @param \Swoole\Http\Response $swooleResponse |
||
| 162 | * |
||
| 163 | * @return \SwooleTW\Http\Transformers\Response |
||
| 164 | */ |
||
| 165 | protected function setSwooleResponse(SwooleResponse $swooleResponse) |
||
| 166 | { |
||
| 167 | $this->swooleResponse = $swooleResponse; |
||
| 168 | |||
| 169 | return $this; |
||
| 170 | } |
||
| 171 | |||
| 172 | /** |
||
| 173 | * @return \Swoole\Http\Response |
||
| 174 | */ |
||
| 175 | public function getSwooleResponse() |
||
| 176 | { |
||
| 177 | return $this->swooleResponse; |
||
| 178 | } |
||
| 179 | |||
| 180 | /** |
||
| 181 | * @param mixed illuminateResponse |
||
| 182 | * |
||
| 183 | * @return \SwooleTW\Http\Transformers\Response |
||
| 184 | */ |
||
| 185 | protected function setIlluminateResponse($illuminateResponse) |
||
| 186 | { |
||
| 187 | if (! $illuminateResponse instanceof SymfonyResponse) { |
||
| 188 | $content = (string) $illuminateResponse; |
||
| 189 | $illuminateResponse = new IlluminateResponse($content); |
||
| 190 | } |
||
| 191 | |||
| 192 | $this->illuminateResponse = $illuminateResponse; |
||
| 193 | |||
| 194 | return $this; |
||
| 195 | } |
||
| 196 | |||
| 197 | /** |
||
| 198 | * @return \Illuminate\Http\Response |
||
| 199 | */ |
||
| 200 | public function getIlluminateResponse() |
||
| 201 | { |
||
| 202 | return $this->illuminateResponse; |
||
| 203 | } |
||
| 204 | |||
| 205 | /** |
||
| 206 | * @param \Swoole\Http\Request $swooleRequest |
||
| 207 | * |
||
| 208 | * @return \SwooleTW\Http\Transformers\Response |
||
| 209 | */ |
||
| 210 | protected function setSwooleRequest(SwooleRequest $swooleRequest) |
||
| 211 | { |
||
| 212 | $this->swooleRequest = $swooleRequest; |
||
| 213 | |||
| 214 | return $this; |
||
| 215 | } |
||
| 216 | |||
| 217 | /** |
||
| 218 | * @return \Swoole\Http\Request |
||
| 219 | */ |
||
| 220 | public function getSwooleRequest() |
||
| 221 | { |
||
| 222 | return $this->swooleRequest; |
||
| 223 | } |
||
| 224 | |||
| 225 | /** |
||
| 226 | * @param string $responseContentEncoding |
||
| 227 | * @return bool |
||
| 228 | */ |
||
| 229 | protected function canGzipContent($responseContentEncoding) |
||
| 230 | { |
||
| 231 | return empty($responseContentEncoding) && |
||
| 232 | config('swoole_http.server.options.http_compression', true) && |
||
| 233 | !empty($this->swooleRequest->header['accept-encoding']) && |
||
| 234 | strpos($this->swooleRequest->header['accept-encoding'], 'gzip') !== false && |
||
| 235 | function_exists('gzencode'); |
||
| 236 | } |
||
| 237 | } |
||
| 238 |
Let?s assume that you have a directory layout like this:
. |-- OtherDir | |-- Bar.php | `-- Foo.php `-- SomeDir `-- Foo.phpand let?s assume the following content of
Bar.php:If both files
OtherDir/Foo.phpandSomeDir/Foo.phpare loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.phpHowever, as
OtherDir/Foo.phpdoes not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: