diff --git a/.travis.yml b/.travis.yml index 7c16234..d78affb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ matrix: include: - php: 5.3 dist: precise + install: composer remove react/mysql --dev --no-interaction # do not install react/mysql example on legacy PHP allow_failures: - php: hhvm diff --git a/README.md b/README.md index 2004a55..9bc064d 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ existing higher-level protocol implementation. * [Plain TCP connections](#plain-tcp-connections) * [Secure TLS connections](#secure-tls-connections) * [HTTP requests](#http-requests) + * [Database tunnel](#database-tunnel) * [Connection timeout](#connection-timeout) * [DNS resolution](#dns-resolution) * [Password authentication](#password-authentication) @@ -323,6 +324,51 @@ When using the `SshSocksConnector` (recommended), this works for both plain HTTP and TLS-encrypted HTTPS requests. When using the `SshProcessConnector`, this only works for plaintext HTTP requests. +### Database tunnel + +We should now have a basic understanding of how we can tunnel any TCP/IP-based +protocol over an SSH proxy server. Besides using this to access "external" +services, this is also particularly useful because it allows you to access +network services otherwise only local to this SSH server from the outside, such +as a firewalled database server. + +For example, this allows us to combine an +[async MySQL database client](https://github.com/friends-of-reactphp/mysql) and +the above SSH proxy server setup, so we can access a firewalled MySQL database +server through an SSH tunnel. Here's the gist: + +```php +$loop = React\EventLoop\Factory::create(); +$proxy = new Clue\React\SshProxy\SshProcessConnector('user@example.com', $loop); + +$uri = 'test:test@localhost/test'; +$factory = new React\MySQL\Factory($loop, $proxy); +$connection = $factory->createLazyConnection($uri); + +$connection->query('SELECT * FROM book')->then( + function (QueryResult $command) { + echo count($command->resultRows) . ' row(s) in set' . PHP_EOL; + }, + function (Exception $error) { + echo 'Error: ' . $error->getMessage() . PHP_EOL; + } +); + +$connection->quit(); + +$loop->run(); +``` + +See also [example #21](examples) for more details. + +This example will automatically launch the `ssh` client binary to create the +connection to a database server that can not otherwise be accessed from the +outside. From the perspective of the database server, this looks just like a +regular, local connection. From this code's perspective, this will create a +regular, local connection which just happens to use a secure SSH tunnel to +transport this to a remote server, so you can send any query like you would to a +local database server. + ### Connection timeout By default, neither the `SshProcessConnector` nor the `SshSocksConnector` implement diff --git a/composer.json b/composer.json index 61633dd..56aea14 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,7 @@ }, "require-dev": { "clue/block-react": "^1.3", - "phpunit/phpunit": "^7.4 || ^6.4 || ^5.0 || ^4.8.36" + "phpunit/phpunit": "^7.4 || ^6.4 || ^5.0 || ^4.8.36", + "react/mysql": "^0.5.3" } } diff --git a/examples/21-mysql-ssh-tunnel.php b/examples/21-mysql-ssh-tunnel.php new file mode 100644 index 0000000..4007554 --- /dev/null +++ b/examples/21-mysql-ssh-tunnel.php @@ -0,0 +1,37 @@ +createLazyConnection($url); + +$client->query('SELECT * FROM (SELECT "foo" UNION SELECT "bar") data')->then(function (QueryResult $query) { + var_dump($query->resultRows); +}, 'printf'); +$client->quit(); + +$loop->run();