├── .gitignore ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src ├── Console │ └── Commands │ │ └── ReactServe.php ├── HttpSession.php ├── Providers │ └── ReactCommandProvider.php └── Server.php └── tests └── bootstrap.php /.gitignore: -------------------------------------------------------------------------------- 1 | phpunit.xml 2 | composer.phar 3 | composer.lock 4 | composer-test.lock 5 | vendor/ 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laravel-reactphp 2 | 3 | ReactPHP Server on Laravel 5.0 4 | 5 | ## install 6 | 7 | - install via composer 8 | 9 | ```sh 10 | composer require nazo/laravel-reactphp 11 | ``` 12 | 13 | - After installing, add provider on config/app.php on your project. 14 | 15 | ```php 16 | // app.php 17 | 18 | 'providers' => [ 19 | ... 20 | 21 | 'LaravelReactPHP\Providers\ReactCommandProvider', 22 | ], 23 | ``` 24 | 25 | ## run server 26 | 27 | ```sh 28 | php artisan react-serve 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nazo/laravel-reactphp", 3 | "type": "library", 4 | "description": "ReactPHP Server On Laravel 5.0", 5 | "keywords": ["ReactPHP", "Laravel", "server"], 6 | "homepage": "http://github.com/nazo/laravel-reactphp", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Takuya Sato", 11 | "email": "takuya0219@gmail.com", 12 | "homepage": "https://github.com/nazo" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.4.0", 17 | "laravel/framework": "5.0.*", 18 | "react/react": "0.4.*" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "~4.0" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "LaravelReactPHP\\": "src/" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "LaravelReactPHP\\Tests\\": "tests/" 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | ./tests/ 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Console/Commands/ReactServe.php: -------------------------------------------------------------------------------- 1 | input->getOption('host'); 31 | 32 | $port = $this->input->getOption('port'); 33 | 34 | $this->info("Laravel ReactPHP server started on http://{$host}:{$port}"); 35 | 36 | with(new \LaravelReactPHP\Server($host, $port))->run(); 37 | } 38 | 39 | /** 40 | * Get the console command options. 41 | * 42 | * @return array 43 | */ 44 | protected function getOptions() 45 | { 46 | return array( 47 | array('host', null, InputOption::VALUE_OPTIONAL, 'The host address to serve the application on.', 'localhost'), 48 | 49 | array('port', null, InputOption::VALUE_OPTIONAL, 'The port to serve the application on.', 8000), 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/HttpSession.php: -------------------------------------------------------------------------------- 1 | host = $host; 34 | $this->port = $port; 35 | } 36 | 37 | protected function getRequestUri(array $headers, $path) 38 | { 39 | $protocol = "http://"; 40 | if (isset($headers['HTTPS'])) { 41 | $protocol = "https://"; 42 | } 43 | $http_host = $protocol.$this->host; 44 | if (isset($headers['Host'])) { 45 | $http_host = $protocol.$headers['Host']; 46 | } 47 | 48 | return $http_host.$path; 49 | } 50 | 51 | protected function getCookies(array $headers) 52 | { 53 | $cookies = []; 54 | if (isset($headers['Cookie'])) { 55 | if (function_exists('http_parse_cookie')) { 56 | $cookie_data = http_parse_cookie($headers['Cookie']); 57 | if ($cookie_data) { 58 | $cookies = $cookie_data->cookies; 59 | } 60 | } else if (class_exists("\Guzzle\Parser\Cookie\CookieParser")) { 61 | $cookies = array_get(with(new \Guzzle\Parser\Cookie\CookieParser())->parseCookie($headers['Cookie']), 'cookies', []); 62 | } else if (class_exists("\GuzzleHttp\Cookie\SetCookie")) { 63 | foreach(\GuzzleHttp\Cookie\SetCookie::fromString($headers['Cookie'])->toArray() as $data) { 64 | $cookies[$data['Name']] = $data['Value']; 65 | } 66 | } 67 | } 68 | 69 | return $cookies; 70 | } 71 | 72 | protected function buildCookies(array $cookies) 73 | { 74 | $headers = []; 75 | foreach ($cookies as $cookie) { 76 | if (!isset($headers['Set-Cookie'])) { 77 | $headers['Set-Cookie'] = []; 78 | } 79 | $cookie_value = sprintf("%s=%s", rawurlencode($cookie->getName()), rawurlencode($cookie->getValue())); 80 | if ($cookie->getDomain()) { 81 | $cookie_value .= sprintf("; Domain=%s", $cookie->getDomain()); 82 | } 83 | if ($cookie->getExpiresTime()) { 84 | $cookie_value .= sprintf("; Max-Age=%s", $cookie->getExpiresTime()); 85 | } 86 | if ($cookie->getPath()) { 87 | $cookie_value .= sprintf("; Path=%s", $cookie->getPath()); 88 | } 89 | if ($cookie->isSecure()) { 90 | $cookie_value .= "; Secure"; 91 | } 92 | if ($cookie->isHttpOnly()) { 93 | $cookie_value .= "; HttpOnly"; 94 | } 95 | $headers['Set-Cookie'][] = $cookie_value; 96 | } 97 | 98 | return $headers; 99 | } 100 | 101 | protected function handleRequest(\React\Http\Request $request, \React\Http\Response $response) 102 | { 103 | $kernel = \App::make('Illuminate\Contracts\Http\Kernel'); 104 | $laravel_request = \Request::create( 105 | $this->getRequestUri($request->getHeaders(), $request->getPath()), 106 | $request->getMethod(), 107 | array_merge($request->getQuery(), $this->post_params), 108 | $this->getCookies($request->getHeaders()), 109 | [], 110 | [], 111 | $this->request_body 112 | ); 113 | $laravel_response = $kernel->handle($laravel_request); 114 | $headers = array_merge($laravel_response->headers->allPreserveCase(), $this->buildCookies($laravel_response->headers->getCookies())); 115 | $response->writeHead($laravel_response->getStatusCode(), $headers); 116 | $response->end($laravel_response->getContent()); 117 | 118 | $kernel->terminate($laravel_request, $laravel_response); 119 | } 120 | 121 | public function handle(\React\Http\Request $request, \React\Http\Response $response) 122 | { 123 | $this->post_params = []; 124 | $request->on('data', function($body) use($request, $response) { 125 | $this->request_body = $body; 126 | parse_str($body, $this->post_params); 127 | 128 | $this->handleRequest($request, $response); 129 | }); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Providers/ReactCommandProvider.php: -------------------------------------------------------------------------------- 1 | 'command.react-serve']; 9 | 10 | public function boot() 11 | { 12 | 13 | } 14 | 15 | public function register() 16 | { 17 | $this->app->singleton('command.react-serve', function() 18 | { 19 | return new ReactServe(); 20 | }); 21 | $this->commands('command.react-serve'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Server.php: -------------------------------------------------------------------------------- 1 | host = $host; 24 | $this->port = $port; 25 | } 26 | 27 | /** 28 | * Running HTTP Server 29 | */ 30 | public function run() 31 | { 32 | $loop = new \React\EventLoop\StreamSelectLoop(); 33 | $socket = new \React\Socket\Server($loop); 34 | $http = new \React\Http\Server($socket, $loop); 35 | $http->on('request', function ($request, $response) { 36 | with(new HttpSession($this->host, $this->port))->handle($request, $response); 37 | }); 38 | $socket->listen($this->port, $this->host); 39 | $loop->run(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 |