Commit 36830edf by hanccc

增加登录方法

1 parent 174552dd
...@@ -9,7 +9,11 @@ ...@@ -9,7 +9,11 @@
} }
], ],
"require": { "require": {
"guzzlehttp/guzzle": "^6.2" "guzzlehttp/guzzle": "^6.2",
"querypath/QueryPath": "^3.0",
"symfony/dom-crawler": "^3.2",
"endroid/qrcode": "^1.7",
"symfony/css-selector": "^3.2"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
......
...@@ -4,10 +4,61 @@ ...@@ -4,10 +4,61 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "f5c4e1f28cd3459bcceea817aeb70175", "hash": "5d864dbf0e5d931155a639d3550d8797",
"content-hash": "a5cd8cbd0f2e29cd0e02a802ac2f7b7e", "content-hash": "43e84ce436c790f7670e8caa6fe63079",
"packages": [ "packages": [
{ {
"name": "endroid/qrcode",
"version": "1.7.4",
"source": {
"type": "git",
"url": "https://github.com/endroid/QrCode.git",
"reference": "ba35ed8f0686bc4ec82874752778ccb427261a41"
},
"dist": {
"type": "zip",
"url": "https://packagist.phpcomposer.com/files/endroid/QrCode/ba35ed8f0686bc4ec82874752778ccb427261a41.zip",
"reference": "ba35ed8f0686bc4ec82874752778ccb427261a41",
"shasum": ""
},
"require": {
"ext-gd": "*",
"php": ">=5.3.0",
"symfony/options-resolver": "^2.3|^3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Endroid\\QrCode\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jeroen van den Enden",
"email": "info@endroid.nl",
"homepage": "http://endroid.nl/"
}
],
"description": "Endroid QR Code",
"homepage": "https://github.com/endroid/QrCode",
"keywords": [
"code",
"endroid",
"qr",
"qrcode"
],
"time": "2016-07-26 09:39:07"
},
{
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
"version": "6.2.2", "version": "6.2.2",
"source": { "source": {
...@@ -179,6 +230,71 @@ ...@@ -179,6 +230,71 @@
"time": "2016-06-24 23:00:38" "time": "2016-06-24 23:00:38"
}, },
{ {
"name": "masterminds/html5",
"version": "2.2.2",
"source": {
"type": "git",
"url": "https://github.com/Masterminds/html5-php.git",
"reference": "7866e93dcf0245de22378414e0c2c7350abc45af"
},
"dist": {
"type": "zip",
"url": "https://packagist.phpcomposer.com/files/Masterminds/html5-php/7866e93dcf0245de22378414e0c2c7350abc45af.zip",
"reference": "7866e93dcf0245de22378414e0c2c7350abc45af",
"shasum": ""
},
"require": {
"ext-libxml": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "4.*",
"sami/sami": "~2.0",
"satooshi/php-coveralls": "1.0.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
}
},
"autoload": {
"psr-4": {
"Masterminds\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Matt Butcher",
"email": "technosophos@gmail.com"
},
{
"name": "Asmir Mustafic",
"email": "goetas@gmail.com"
},
{
"name": "Matt Farina",
"email": "matt@mattfarina.com"
}
],
"description": "An HTML5 parser and serializer.",
"homepage": "http://masterminds.github.io/html5-php",
"keywords": [
"HTML5",
"dom",
"html",
"parser",
"querypath",
"serializer",
"xml"
],
"time": "2016-09-22 11:01:11"
},
{
"name": "psr/http-message", "name": "psr/http-message",
"version": "1.0.1", "version": "1.0.1",
"source": { "source": {
...@@ -227,6 +343,270 @@ ...@@ -227,6 +343,270 @@
"response" "response"
], ],
"time": "2016-08-06 14:39:51" "time": "2016-08-06 14:39:51"
},
{
"name": "querypath/querypath",
"version": "3.0.5",
"source": {
"type": "git",
"url": "https://github.com/technosophos/querypath.git",
"reference": "6b8e2395fac61fac25bbe962f94def556cb85f7d"
},
"dist": {
"type": "zip",
"url": "https://packagist.phpcomposer.com/files/technosophos/querypath/6b8e2395fac61fac25bbe962f94def556cb85f7d.zip",
"reference": "6b8e2395fac61fac25bbe962f94def556cb85f7d",
"shasum": ""
},
"require": {
"masterminds/html5": "2.*",
"php": ">=5.3.0"
},
"type": "library",
"autoload": {
"psr-0": {
"QueryPath": "src/"
},
"files": [
"src/qp_functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "HTML/XML querying (CSS 4 or XPath) and processing (like jQuery)",
"homepage": "https://github.com/technosophos/querypath",
"keywords": [
"css",
"html",
"jquery",
"xml",
"xslt"
],
"time": "2016-08-01 22:40:30"
},
{
"name": "symfony/css-selector",
"version": "v3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
"reference": "e1241f275814827c411d922ba8e64cf2a00b2994"
},
"dist": {
"type": "zip",
"url": "https://packagist.phpcomposer.com/files/symfony/css-selector/e1241f275814827c411d922ba8e64cf2a00b2994.zip",
"reference": "e1241f275814827c411d922ba8e64cf2a00b2994",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\CssSelector\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jean-François Simon",
"email": "jeanfrancois.simon@sensiolabs.com"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
"time": "2016-11-03 08:11:03"
},
{
"name": "symfony/dom-crawler",
"version": "v3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "c6b6111f5aae7c58698cdc10220785627ac44a2c"
},
"dist": {
"type": "zip",
"url": "https://packagist.phpcomposer.com/files/symfony/dom-crawler/c6b6111f5aae7c58698cdc10220785627ac44a2c.zip",
"reference": "c6b6111f5aae7c58698cdc10220785627ac44a2c",
"shasum": ""
},
"require": {
"php": ">=5.5.9",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"symfony/css-selector": "~2.8|~3.0"
},
"suggest": {
"symfony/css-selector": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\DomCrawler\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
"time": "2016-11-25 12:32:42"
},
{
"name": "symfony/options-resolver",
"version": "v3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "45940bcad6388b3b6058107eca67ced738d205bb"
},
"dist": {
"type": "zip",
"url": "https://packagist.phpcomposer.com/files/symfony/options-resolver/45940bcad6388b3b6058107eca67ced738d205bb.zip",
"reference": "45940bcad6388b3b6058107eca67ced738d205bb",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\OptionsResolver\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony OptionsResolver Component",
"homepage": "https://symfony.com",
"keywords": [
"config",
"configuration",
"options"
],
"time": "2016-05-13 18:13:23"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "e79d363049d1c2128f133a2667e4f4190904f7f4"
},
"dist": {
"type": "zip",
"url": "https://packagist.phpcomposer.com/files/symfony/polyfill-mbstring/e79d363049d1c2128f133a2667e4f4190904f7f4.zip",
"reference": "e79d363049d1c2128f133a2667e4f4190904f7f4",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"time": "2016-11-14 01:06:16"
} }
], ],
"packages-dev": [], "packages-dev": [],
......
...@@ -9,24 +9,73 @@ ...@@ -9,24 +9,73 @@
namespace Hanson\Robot; namespace Hanson\Robot;
use Endroid\QrCode\QrCode;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use Symfony\Component\DomCrawler\Crawler;
class Robot class Robot
{ {
private $client; private $client;
public $tmpPath;
private $uuid; private $uuid;
private $baseUri; private $baseUri = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin';
private $baseHost; private $baseHost = 'wx2.qq.com';
private $redirectUri; private $redirectUri;
public function __construct() private $skey;
private $sid;
private $uin;
private $passTicket;
private $deviceId;
private $baseRequest;
public function __construct(Array $option = [])
{ {
$this->client = new Client(); $this->client = new Client();
$this->handleOption($option);
}
/**
* 处理option
*
* @param $option
*/
private function handleOption($option)
{
$this->tmpPath = $option['tmp'] ?? sys_get_temp_dir();
}
public function run()
{
$this->getUuid();
$this->generateQrCode();
$this->log('[INFO] 请用微信扫码');
if($this->waitForLogin() !== 200){
die('[ERROR] 微信登录失败');
}
if(!$this->login()){
die('[ERROR] 登录失败');
}
$this->log('[INFO] 登录成功');
$this->init();
} }
/** /**
...@@ -53,6 +102,115 @@ class Robot ...@@ -53,6 +102,115 @@ class Robot
$this->uuid = $matches[2]; $this->uuid = $matches[2];
} }
/**
* 生成登录二维码
*/
public function generateQrCode()
{
$url = 'https://login.weixin.qq.com/l/' . $this->uuid;
$qrCode = new QrCode($url);
$file = $this->tmpPath . 'login_qr_code.png';
$qrCode->save($file);
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
system($file);
}
}
/**
* 等待登录
*
* @return int
*/
public function waitForLogin(): int
{
$urlTemplate = 'https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?tip=%s&uuid=%s&_=%s';
$retryTime = 10;
$tip = 1;
$code = 0;
while($retryTime > 0){
$url = sprintf($urlTemplate, $tip, $this->uuid, time());
$content = $this->client->get($url)->getBody()->getContents();
preg_match('/window.code=(\d+);/', $content, $matches);
$code = $matches[1];
switch($code){
case '201':
$this->log('[INFO] 请点击确认进行登录');
$tip = 0;
break;
case '200':
preg_match('/window.redirect_uri="(\S+?)";/', $content, $matches);
$this->redirectUri = $matches[1] . '&fun=new';
return $code;
case '408':
$this->log('[ERROR] 微信登录超时。将在 1 秒后重试');
$tip = 1;
$retryTime -= 1;
sleep(1);
break;
default:
$this->log('[ERROR] 微信登录异常。异常码:%s 。1 秒后重试', $code);
$tip = 1;
$retryTime -= 1;
sleep(1);
break;
}
}
return $code;
}
public function login()
{
$content = $this->client->get($this->redirectUri)->getBody()->getContents();
$crawler = new Crawler($content);
$this->skey = $crawler->filter('error skey')->text();
$this->sid = $crawler->filter('error wxsid')->text();
$this->uin = $crawler->filter('error wxuin')->text();
$this->passTicket = $crawler->filter('error pass_ticket')->text();
if(in_array('', [$this->skey, $this->sid, $this->uin, $this->passTicket])){
return false;
}
$this->deviceId = 'e' . strval(random_int(100000000000000, 999999999999999));
$this->baseRequest = [
'Uin' => $this->uin,
'Sid' => $this->sid,
'Skey' => $this->skey,
'DeviceID' => $this->deviceId
];
return true;
}
public function init()
{
$url = sprintf($this->baseUri . '/webwxinit?r=%i&lang=en_US&pass_ticket=%s', time(), $this->passTicket);
$content = $this->client->post($url, [
'query' => [
'BaseRequest' => json_encode($this->baseRequest)
]
])->getBody()->getContents();
print_r($content);
}
private function log($msg, ...$args)
{
echo sprintf($msg . PHP_EOL, $args);
}
public function __get($value) public function __get($value)
{ {
return $this->$value; return $this->$value;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
require_once __DIR__ . './../vendor/autoload.php'; require_once __DIR__ . './../vendor/autoload.php';
$robot = new \Hanson\Robot\Robot();
$robot->getUuid();
echo $robot->uuid;
\ No newline at end of file \ No newline at end of file
$robot = new \Hanson\Robot\Robot(['tmp' => realpath('./tmp') . '/']);
echo $robot->run();
echo 'finish';
//echo $robot->uuid;
\ No newline at end of file \ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!