src/Client.php
public function connect($uri)
    {
        if (strpos($uri, '://') === false) {
            $uri = 'tcp://' . $uri;
        }

        $parts = parse_url($uri);
        if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
            return Promise\reject(new InvalidArgumentException('Invalid target URI specified'));
        }

        $host = trim($parts['host'], '[]');
        $port = $parts['port'];

        if (strlen($host) > 255 || $port > 65535 || $port < 0 || (string)$port !== (string)(int)$port) {
            return Promise\reject(new InvalidArgumentException('Invalid target specified'));
        }

        // construct URI to SOCKS server to connect to
        $socksUri = $this->socksUri;

        // append path from URI if given
        if (isset($parts['path'])) {
            $socksUri .= $parts['path'];
        }

        // parse query args
        $args = array();
        if (isset($parts['query'])) {
            parse_str($parts['query'], $args);
        }

        // append hostname from URI to query string unless explicitly given
        if (!isset($args['hostname'])) {
            $args['hostname'] = $host;
        }

        // append query string
        $socksUri .= '?' . http_build_query($args, '', '&');

        // append fragment from URI if given
        if (isset($parts['fragment'])) {
            $socksUri .= '#' . $parts['fragment'];
        }

        // start TCP/IP connection to SOCKS server
        $connecting = $this->connector->connect($socksUri);

        $deferred = new Deferred(function ($_, $reject) use ($uri, $connecting) {
            $reject(new RuntimeException(
                'Connection to ' . $uri . ' cancelled while waiting for proxy (ECONNABORTED)',
                defined('SOCKET_ECONNABORTED') ? SOCKET_ECONNABORTED : 103
            ));

            // either close active connection or cancel pending connection attempt
            $connecting->then(function (ConnectionInterface $stream) {
                $stream->close();
            });
            $connecting->cancel();
        });

        // handle SOCKS protocol once connection is ready
        // resolve plain connection once SOCKS protocol is completed
        $that = $this;
        $connecting->then(
            function (ConnectionInterface $stream) use ($that, $host, $port, $deferred, $uri) {
                $that->handleConnectedSocks($stream, $host, $port, $deferred, $uri);
            },
            function (Exception $e) use ($uri, $deferred) {
                $deferred->reject($e = new RuntimeException(
                    'Connection to ' . $uri . ' failed because connection to proxy failed (ECONNREFUSED)',
                    defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111,
                    $e
                ));

                // avoid garbage references by replacing all closures in call stack.
                // what a lovely piece of code!
                $r = new \ReflectionProperty('Exception', 'trace');
                $r->setAccessible(true);
                $trace = $r->getValue($e);
                foreach ($trace as &$one) {
                    foreach ($one['args'] as &$arg) {
                        if ($arg instanceof \Closure) {
                            $arg = 'Object(' . get_class($arg) . ')';
                        }
                    }
                }
                $r->setValue($e, $trace);
            }
        );

        return $deferred->promise();
    }
public function connect($uri)
    {
        if (strpos($uri, '://') === false) {
            $uri = 'tcp://' . $uri;
        }

        $parts = parse_url($uri);
        if (!$parts || !isset($parts['scheme'], $parts['host'], $parts['port']) || $parts['scheme'] !== 'tcp') {
            return Promise\reject(new InvalidArgumentException('Invalid target URI specified'));
        }

        $host = trim($parts['host'], '[]');
        $port = $parts['port'];

        if (strlen($host) > 255 || $port > 65535 || $port < 0 || (string)$port !== (string)(int)$port) {
            return Promise\reject(new InvalidArgumentException('Invalid target specified'));
        }

        // construct URI to SOCKS server to connect to
        $socksUri = $this->socksUri;

        // append path from URI if given
        if (isset($parts['path'])) {
            $socksUri .= $parts['path'];
        }

        // parse query args
        $args = array();
        if (isset($parts['query'])) {
            parse_str($parts['query'], $args);
        }

        // append hostname from URI to query string unless explicitly given
        if (!isset($args['hostname'])) {
            $args['hostname'] = $host;
        }

        // append query string
        $socksUri .= '?' . http_build_query($args, '', '&');

        // append fragment from URI if given
        if (isset($parts['fragment'])) {
            $socksUri .= '#' . $parts['fragment'];
        }

        // start TCP/IP connection to SOCKS server
        $connecting = $this->connector->connect($socksUri);

        $deferred = new Deferred(function ($_, $reject) use ($uri, $connecting) {
            $reject(new RuntimeException(
                'Connection to ' . $uri . ' cancelled while waiting for proxy (ECONNABORTED)',
                defined('SOCKET_ECONNABORTED') ? SOCKET_ECONNABORTED : 103
            ));

            // either close active connection or cancel pending connection attempt
            $connecting->then(function (ConnectionInterface $stream) {
                $stream->close();
            });
            $connecting->cancel();
        });

        // handle SOCKS protocol once connection is ready
        // resolve plain connection once SOCKS protocol is completed
        $that = $this;
        $connecting->then(
            function (ConnectionInterface $stream) use ($that, $host, $port, $deferred, $uri) {
                $that->handleConnectedSocks($stream, $host, $port, $deferred, $uri);
            },
            function (Exception $e) use ($uri, $deferred) {
                $deferred->reject($e = new RuntimeException(
                    'Connection to ' . $uri . ' failed because connection to proxy failed (ECONNREFUSED)',
                    defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111,
                    $e
                ));

                // avoid garbage references by replacing all closures in call stack.
                // what a lovely piece of code!
                $r = new \ReflectionProperty('Exception', 'trace');
                $r->setAccessible(true);
                $trace = $r->getValue($e);
                foreach ($trace as &$one) {
                    foreach ($one['args'] as &$arg) {
                        if ($arg instanceof \Closure) {
                            $arg = 'Object(' . get_class($arg) . ')';
                        }
                    }
                }
                $r->setValue($e, $trace);
            }
        );

        return $deferred->promise();
    }
public function connect ( $ uri ) { if ( strpos ( $ uri , '://' ) === false ) { $ uri = 'tcp://' . $ uri ; } $ parts = parse_url ( $ uri ) ; if ( ! $ parts || ! isset ( $ parts [ 'scheme' ] , $ parts [ 'host' ] , $ parts [ 'port' ] ) || $ parts [ 'scheme' ] !== 'tcp' ) { return Promise \ reject ( new InvalidArgumentException ( 'Invalid target URI specified' ) ) ; } $ host = trim ( $ parts [ 'host' ] , '[]' ) ; $ port = $ parts [ 'port' ] ; if ( strlen ( $ host ) > 255 || $ port > 65535 || $ port < 0 || ( string ) $ port !== ( string ) ( int ) $ port ) { return Promise \ reject ( new InvalidArgumentException ( 'Invalid target specified' ) ) ; } // construct URI to SOCKS server to connect to $ socksUri = $ this -> socksUri ; // append path from URI if given if ( isset ( $ parts [ 'path' ] ) ) { $ socksUri .= $ parts [ 'path' ] ; } // parse query args $ args = array ( ) ; if ( isset ( $ parts [ 'query' ] ) ) { parse_str ( $ parts [ 'query' ] , $ args ) ; } // append hostname from URI to query string unless explicitly given if ( ! isset ( $ args [ 'hostname' ] ) ) { $ args [ 'hostname' ] = $ host ; } // append query string $ socksUri .= '?' . http_build_query ( $ args , '' , '&' ) ; // append fragment from URI if given if ( isset ( $ parts [ 'fragment' ] ) ) { $ socksUri .= '#' . $ parts [ 'fragment' ] ; } // start TCP/IP connection to SOCKS server $ connecting = $ this -> connector -> connect ( $ socksUri ) ; $ deferred = new Deferred ( function ( $ _ , $ reject ) use ( $ uri , $ connecting ) { $ reject ( new RuntimeException ( 'Connection to ' . $ uri . ' cancelled while waiting for proxy (ECONNABORTED)' , defined ( 'SOCKET_ECONNABORTED' ) ? SOCKET_ECONNABORTED : 103 ) ) ; // either close active connection or cancel pending connection attempt $ connecting -> then ( function ( ConnectionInterface $ stream ) { $ stream -> close ( ) ; } ) ; $ connecting -> cancel ( ) ; } ) ; // handle SOCKS protocol once connection is ready // resolve plain connection once SOCKS protocol is completed $ that = $ this ; $ connecting -> then ( function ( ConnectionInterface $ stream ) use ( $ that , $ host , $ port , $ deferred , $ uri ) { $ that -> handleConnectedSocks ( $ stream , $ host , $ port , $ deferred , $ uri ) ; } , function ( Exception $ e ) use ( $ uri , $ deferred ) { $ deferred -> reject ( $ e = new RuntimeException ( 'Connection to ' . $ uri . ' failed because connection to proxy failed (ECONNREFUSED)' , defined ( 'SOCKET_ECONNREFUSED' ) ? SOCKET_ECONNREFUSED : 111 , $ e ) ) ; // avoid garbage references by replacing all closures in call stack. // what a lovely piece of code! $ r = new \ ReflectionProperty ( 'Exception' , 'trace' ) ; $ r -> setAccessible ( true ) ; $ trace = $ r -> getValue ( $ e ) ; foreach ( $ trace as & $ one ) { foreach ( $ one [ 'args' ] as & $ arg ) { if ( $ arg instanceof \ Closure ) { $ arg = 'Object(' . get_class ( $ arg ) . ')' ; } } } $ r -> setValue ( $ e , $ trace ) ; } ) ; return $ deferred -> promise ( ) ; }
Establish a TCP/IP connection to the given target URI through the SOCKS server

Many higher-level networking protocols build on top of TCP. It you're dealing
with one such client implementation,  it probably uses/accepts an instance
implementing ReactPHP's `ConnectorInterface` (and usually its default `Connector`
instance). In this case you can also pass this `Connector` instance instead
to make this client implementation SOCKS-aware. That's it.

@param string $uri
@return PromiseInterface Promise<ConnectionInterface,Exception>
Establish a TCP / IP connection to the given target URI through the SOCKS server