With the popularity of wechat, scanning code login is increasingly used by current applications. Because it does not need to remember the password, as long as there is a wechat signal can be convenient and fast login. Wechat’s open platform supports the function of scanning code login, but most people are still using the public platform, so the scanning code login can only be realized by themselves. This is based on the temporary TWO-DIMENSIONAL code with parameters of wechat public platform, and combined with The WebSocket service of Swoole to realize the scanning code login. The general process is as follows:

  1. The client opens the login page and connects to the WebSocket service

  2. The WebScoket service generates a QR code with parameters and returns it to the client

  3. The user scans the qr code with parameters displayed

  4. The wechat server calls back the code sweep event and notifies the developer server

  5. The developer server notifies the WebSocket service

  6. The WebSocket service notifies the client of successful login

Connect to the WebSocket service

Once Swoole is installed, we need to use the WebSocket service. Creating a WebSocket service is very simple:

$server = new swoole_websocket_server("0.0.0.0", 1099);
$server->on('open', function (swoole_websocket_server $server, $request) use ($config){
    echo "server: handshake success with fd{$request->fd}\n";
});

$server->on('message', function (swoole_websocket_server $server, $frame) {

});
Copy the code

The message callback here is not really needed because the server sends messages, but one must be set. If the port number is lower than 1024, you must have the root permission. The server must enable the port on the firewall.

Generate a QR code with parameters

After the WebSocket service is successfully connected to the client, it needs to generate a wechat QR code with parameters and return it to the client for display:

$server->on('open', function (swoole_websocket_server $server, $request) use ($config){
    $app = Factory::officialAccount($config['wechat']);
    $result = $app->qrcode->temporary($request->fd, 120);
    $url = $app->qrcode->url($result['ticket']);
    $server->push($request->fd, json_encode([
        'message_type'    =>  'qrcode_url',
        'url'       =>  $url
    ]));
});
Copy the code

In the open callback, we generate a temporary QR code whose scene value is the file descriptor for the client connection to ensure that each client is unique. The valid time is set to 120 seconds to prevent one QR code from being scanned for multiple times. The message pushed to the client must be JSON for the client to process. The client code is also simple:

Const socket = new WebSocket('ws://127.0.0.1:1099'); socket.addEventListener('message', function (event) { var data = JSON.parse(event.data); if (data.message_type == 'qrcode_url'){ $('#qrcode').attr('src', data.url); }});Copy the code

Callback sweep event

After displaying the QR code on the client, you need to prompt the user to scan the code. For the user to scan the temporary QR code, wechat will trigger the corresponding callback event, and we need to process the user’s code scanning behavior in this callback event. Among them, we need to use some parameters transmitted by wechat:

FromUserName Sender account (one OpenID) MsgType Message type, event Event event type, SUBSCRIBE EventKey Event KEY value, qrScene_ prefix, followed by the parameters of the QR codeCopy the code

Note here: Wechat scan push EventKey does not have the prefix qrscene_, only not scan and then follow.

After receiving wechat callback, we should first do different processing according to different event types:

If ($message['MsgType'] == 'event'){if ($message[' event'] == 'subscribe'){return $this->subscribe($message); } if ($message['Event'] == 'unsubscribe') {return $this->unsubscribe($message); $this-> SCAN ($message); $this-> SCAN ($message); }}else{return "Hello! Welcome to use SwooleWechat scan login "; }Copy the code

Only one event-focused business logic is explained here, and the rest is coded as needed:

public function subscribe($message){ $eventKey = intval(str_replace('qrscene_', '', $message['EventKey'])); $openId = $message['FromUserName']; $user = $this->app->user->get($openId); $this->notify(json_encode([ 'type' => 'scan', 'fd' => $eventKey, 'nickname' => $user['nickname'] ])); $count = $this->count($openId); $msgTemp = "%s" \n This is your %s login, have fun!" ; return sprintf($msgTemp, $user['nickname'], $count); }Copy the code

The EventKey here is actually the client file descriptor that connects to WebSocket, obtains the OPEN_ID of the scanned user, obtains the user information according to the OPEN_ID of the user, informs the WebSocket service, and responds to the text message to wechat.

A troublesome point here is how to notify the WebSocket service, we know that the code handling wechat callback is not on the WebSocket service, so how to communicate between different servers? Swoole’s official solution is two:

  1. Listen for an additional UDP port

  2. Use swoole_client as the client to access the Server

Here we choose the second solution, Swoole 1.8 supports a Server to listen on multiple ports, we add a TCP port in WebSocket service:

$tcp_server = $server->addListener('0.0.0.0', 9999, SWOOLE_SOCK_TCP);
$tcp_server->set([]);
$tcp_server->on('receive', function ($serv, $fd, $threadId, $data) {

});
Copy the code

The primary Server is WebSocket or Http. The TCP port monitored by the new Server inherits the protocol Settings of the primary Server by default. The new protocol can be enabled only after the set method is invoked to set the new protocol

We can then notify the WebSocket service in the sweep callback process:

public function notify($message){
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    if (!$client->connect('127.0.0.1', $this->config['notify_port'], -1)) {
        return "connect failed. Error: {$client->errCode}\n";
    }
    $ret = $client->send($message);
}
Copy the code

Notification of Successful Login

After the WebSocket service receives a successful login notification, it can process the user information as needed and then pass the user information to the client’s browser to display the results. Remember the TCP port we just listened on? You can handle it in the receive event:

$tcp_server->on('receive', function ($serv, $fd, $threadId, $data) {
    $data = json_decode($data, true);
    if ($data['type'] == 'scan'){
        $serv->push($data['fd'], json_encode([
            'message_type'    =>  'scan_success',
            'user'  =>  $data['nickname']
        ]));
    }
    $serv->close($fd);
});
Copy the code

Last login interface:

Hair figure too much trouble, go to http://wechat.sunnyshift.com/index.php to test the address.

Pay attention and don’t get lost

All right, everybody, that’s all for this article. All the people here are talented. As I said before, there are many technical points in PHP, because there are too many, it is really difficult to write, you will not read too much after writing, so I have compiled it into PDF and document, if necessary

Click on the code: PHP+ “platform”

As long as you can guarantee your salary to rise a step (constantly updated)

I hope the above content can help you. Many PHPer will encounter some problems and bottlenecks when they are advanced, and they have no sense of direction when writing too many business codes. I have sorted out some information, including but not limited to: Distributed architecture, high scalability, high performance, high concurrency, server performance tuning, TP6, Laravel, YII2, Redis, Swoole, Swoft, Kafka, Mysql optimization, shell scripting, Docker, microservices, Nginx, etc