├── LICENSE
├── alipay_donate.jpg
├── .gitignore
├── src
├── TekinTCaptcha
│ ├── RequestMethod.php
│ ├── RequestMethod
│ │ ├── Curl.php
│ │ ├── Post.php
│ │ ├── Get.php
│ │ ├── Socket.php
│ │ ├── CurlPost.php
│ │ ├── CurlGet.php
│ │ └── SocketPost.php
│ ├── TekinTCaptcha.php
│ ├── RequestParameters.php
│ └── Response.php
└── autoload.php
├── .travis.yml
├── phpunit.xml
├── composer.json
├── tests
└── TekinTCaptcha
│ ├── RequestMethod
│ ├── CurlPostTest.php
│ ├── SocketPostTest.php
│ └── PostTest.php
│ ├── RequestParametersTest.php
│ ├── TekinTCaptchaTest.php
│ └── ResponseTest.php
├── examples
├── index.html
└── login.php
└── README.md
/LICENSE:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tekintian/TekinTCaptcha/HEAD/LICENSE
--------------------------------------------------------------------------------
/alipay_donate.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tekintian/TekinTCaptcha/HEAD/alipay_donate.jpg
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /composer.lock
2 | /vendor/
3 | /reports/
4 | *.sublime-project
5 | *.sublime-workspace
6 |
--------------------------------------------------------------------------------
/src/TekinTCaptcha/RequestMethod.php:
--------------------------------------------------------------------------------
1 | > ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini ; true
17 | - phpenv version-name | grep ^5.[34] && echo "apc.enable_cli=1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini ; true
18 |
19 | script:
20 | - vendor/bin/phpunit
21 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
Complete the Tekin TencentCAPTCHA then submit the form.
9 | 26 | 27 | 45 | 46 | -------------------------------------------------------------------------------- /src/TekinTCaptcha/RequestMethod/Post.php: -------------------------------------------------------------------------------- 1 | array( 34 | 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 35 | 'method' => 'POST', 36 | 'content' => $params->toQueryString(), 37 | // Force the peer to validate (not needed in 5.6.0+, but still works) 38 | 'verify_peer' => true, 39 | // Force the peer validation to use www.google.com 40 | $peer_key => 'www.yunnan.ws', 41 | ), 42 | ); 43 | 44 | $context = stream_context_create($options); 45 | return file_get_contents(self::TCAPTCHA_VERIFY_URL, false, $context); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/TekinTCaptcha/RequestMethod/Get.php: -------------------------------------------------------------------------------- 1 | array( 34 | // 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 35 | 'method' => 'GET', 36 | 'content' => $params->toQueryString(), 37 | // Force the peer to validate (not needed in 5.6.0+, but still works) 38 | // 'verify_peer' => true, 39 | // Force the peer validation to use www.google.com 40 | // $peer_key => 'www.yunnan.ws', 41 | ), 42 | ); 43 | 44 | $context = stream_context_create($options); 45 | 46 | return file_get_contents(self::TCAPTCHA_VERIFY_URL, false, $context); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/TekinTCaptcha/TekinTCaptchaTest.php: -------------------------------------------------------------------------------- 1 | verify(''); 32 | $this->assertFalse($Ticket->isSuccess()); 33 | $this->assertEquals(array('missing-input-ticket'), $Ticket->getErrMsg()); 34 | } 35 | 36 | public function testVerifyReturnsErrorOnMissingRandstr() 37 | { 38 | $rc = new TekinTCaptcha('Ticket','Randstr'); 39 | $Ticket = $rc->verify('Ticket'); 40 | $this->assertFalse($Ticket->isSuccess()); 41 | $this->assertEquals(array('missing-input-randstr'), $Ticket->getErrMsg()); 42 | } 43 | public function testVerifyReturnsResponse() 44 | { 45 | $method = $this->getMock('\\TekinTCaptcha\\RequestMethod', array('submit')); 46 | $method->expects($this->once()) 47 | ->method('submit') 48 | ->with($this->callback(function ($params) { 49 | 50 | return true; 51 | })) 52 | ->will($this->returnValue('{"success": true}')); 53 | ; 54 | $rc = new TekinTCaptcha('aid','AppSecretKey', $method); 55 | $Ticket = $rc->verify('Ticket','Randstr'); 56 | $this->assertTrue($Ticket->isSuccess()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/TekinTCaptcha/RequestMethod/Socket.php: -------------------------------------------------------------------------------- 1 | handle = fsockopen($hostname, $port, $errno, $errstr, (is_null($timeout) ? ini_get("default_socket_timeout") : $timeout)); 27 | 28 | if ($this->handle != false && $errno === 0 && $errstr === '') { 29 | return $this->handle; 30 | } 31 | return false; 32 | } 33 | 34 | /** 35 | * fwrite 36 | * 37 | * @see http://php.net/fwrite 38 | * @param string $string 39 | * @param int $length 40 | * @return int | bool 41 | */ 42 | public function fwrite($string, $length = null) 43 | { 44 | return fwrite($this->handle, $string, (is_null($length) ? strlen($string) : $length)); 45 | } 46 | 47 | /** 48 | * fgets 49 | * 50 | * @see http://php.net/fgets 51 | * @param int $length 52 | * @return string 53 | */ 54 | public function fgets($length = null) 55 | { 56 | return fgets($this->handle, $length); 57 | } 58 | 59 | /** 60 | * feof 61 | * 62 | * @see http://php.net/feof 63 | * @return bool 64 | */ 65 | public function feof() 66 | { 67 | return feof($this->handle); 68 | } 69 | 70 | /** 71 | * fclose 72 | * 73 | * @see http://php.net/fclose 74 | * @return bool 75 | */ 76 | public function fclose() 77 | { 78 | return fclose($this->handle); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/TekinTCaptcha/RequestMethod/CurlPost.php: -------------------------------------------------------------------------------- 1 | curl = $curl; 31 | } else { 32 | $this->curl = new Curl(); 33 | } 34 | } 35 | 36 | /** 37 | * Submit the cURL request with the specified parameters. 38 | * 39 | * @param RequestParameters $params Request parameters 40 | * @return string Body of the TekinTCaptcha response 41 | */ 42 | public function submit(RequestParameters $params) 43 | { 44 | $handle = $this->curl->init(self::TCAPTCHA_VERIFY_URL); 45 | 46 | $options = array( 47 | CURLOPT_POST => true, 48 | CURLOPT_POSTFIELDS => $params->toQueryString(), 49 | CURLOPT_HTTPHEADER => array( 50 | 'Content-Type: application/x-www-form-urlencoded' 51 | ), 52 | CURLINFO_HEADER_OUT => false, 53 | CURLOPT_HEADER => false, 54 | CURLOPT_DNS_USE_GLOBAL_CACHE => true, 55 | CURLOPT_RETURNTRANSFER => true, 56 | CURLOPT_SSL_VERIFYPEER => true 57 | ); 58 | $this->curl->setoptArray($handle, $options); 59 | 60 | $rawResponse = $this->curl->exec($handle); 61 | $this->curl->close($handle); 62 | 63 | return $rawResponse; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/TekinTCaptcha/RequestMethod/CurlGet.php: -------------------------------------------------------------------------------- 1 | curl = $curl; 31 | } else { 32 | $this->curl = new Curl(); 33 | } 34 | } 35 | 36 | /** 37 | * Submit the cURL request with the specified parameters. 38 | * 39 | * @param RequestParameters $params Request parameters 40 | * @return string Body of the TekinTCaptcha response 41 | */ 42 | public function submit(RequestParameters $params) 43 | { 44 | $handle = $this->curl->init(); 45 | 46 | $options = array( 47 | CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, 48 | CURLOPT_HTTPGET => true, 49 | CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22', 50 | CURLOPT_URL => self::TCAPTCHA_VERIFY_URL.'?'.$params->toQueryString(), 51 | CURLOPT_TIMEOUT => 30, 52 | CURLOPT_CONNECTTIMEOUT => 30, 53 | CURLOPT_RETURNTRANSFER => true, 54 | CURLOPT_SSL_VERIFYHOST => false, 55 | CURLOPT_SSL_VERIFYPEER => false 56 | ); 57 | $this->curl->setoptArray($handle, $options); 58 | 59 | $rawResponse = $this->curl->exec($handle); 60 | $this->curl->close($handle); 61 | 62 | return $rawResponse; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/TekinTCaptcha/ResponseTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($success, $Ticket->isSuccess()); 16 | $this->assertEquals($msg, $Ticket->getErrMsg()); 17 | $this->assertEquals($status, $Ticket->getStatus()); 18 | $this->assertEquals($evil_level, $Ticket->getEvilLevel()); 19 | } 20 | 21 | public function provideJson() 22 | { 23 | return array( 24 | array('{"success": true}', true, array(), 1,null), 25 | array('{"success": true, "err_msg": "OK"}', true, array(), 1,null), 26 | array('{"success": false, "err_msg": ["test"]}', false, array('test'), 0, null), 27 | array('{"success": false, "err_msg": ["test"], "response": "0"}', false, array('test'), 0, null), 28 | array('{"success": true, "err_msg": ["test"]}', true, array(),1, null), 29 | array('{"success": true, "err_msg": ["OK"], "response": "1"}', true, array(), '1',10), 30 | array('{"success": false}', false, array(), 0, null), 31 | 32 | array('BAD JSON', false, array('invalid-json'), -1, null), 33 | ); 34 | } 35 | 36 | public function testIsSuccess() 37 | { 38 | $Ticket = new Response(true); 39 | $this->assertTrue($Ticket->isSuccess()); 40 | 41 | $Ticket = new Response(false); 42 | $this->assertFalse($Ticket->isSuccess()); 43 | 44 | $Ticket = new Response(true, array(), 1); 45 | $this->assertEquals('1', $Ticket->getStatus()); 46 | } 47 | 48 | public function testGetErrMsg() 49 | { 50 | $errMsg = array('test'); 51 | $Ticket = new Response(true, $errMsg); 52 | $this->assertEquals($errMsg, $Ticket->getErrMsg()); 53 | } 54 | 55 | public function testGetStatus() 56 | { 57 | $status = 1; 58 | $errMsg = array(); 59 | $Ticket = new Response(true, $errMsg, $status); 60 | $this->assertEquals($status, $Ticket->getStatus()); 61 | } 62 | 63 | public function testGetEvilLevel() 64 | { 65 | $evilLevel = 10; 66 | $errMsg = array(); 67 | $Ticket = new Response(true, $errMsg, 1, $evilLevel); 68 | $this->assertEquals($evilLevel, $Ticket->getEvilLevel()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tests/TekinTCaptcha/RequestMethod/SocketPostTest.php: -------------------------------------------------------------------------------- 1 | getMock('\\TekinTCaptcha\\RequestMethod\\Socket', array('fsockopen', 'fwrite', 'fgets', 'feof', 'fclose')); 14 | $socket->expects($this->once()) 15 | ->method('fsockopen') 16 | ->willReturn(true); 17 | $socket->expects($this->once()) 18 | ->method('fwrite'); 19 | $socket->expects($this->once()) 20 | ->method('fgets') 21 | ->willReturn("HTTP/1.1 200 OK\n\nRESPONSEBODY"); 22 | $socket->expects($this->exactly(2)) 23 | ->method('feof') 24 | ->will($this->onConsecutiveCalls(false, true)); 25 | $socket->expects($this->once()) 26 | ->method('fclose') 27 | ->willReturn(true); 28 | 29 | $ps = new SocketPost($socket); 30 | $response = $ps->submit(new RequestParameters("aid","AppSecretKey", "Ticket","Randstr","UserIP")); 31 | $this->assertEquals('RESPONSEBODY', $response); 32 | } 33 | 34 | public function testSubmitBadResponse() 35 | { 36 | $socket = $this->getMock('\\TekinTCaptcha\\RequestMethod\\Socket', array('fsockopen', 'fwrite', 'fgets', 'feof', 'fclose')); 37 | $socket->expects($this->once()) 38 | ->method('fsockopen') 39 | ->willReturn(true); 40 | $socket->expects($this->once()) 41 | ->method('fwrite'); 42 | $socket->expects($this->once()) 43 | ->method('fgets') 44 | ->willReturn("HTTP/1.1 500 NOPEn\\nBOBBINS"); 45 | $socket->expects($this->exactly(2)) 46 | ->method('feof') 47 | ->will($this->onConsecutiveCalls(false, true)); 48 | $socket->expects($this->once()) 49 | ->method('fclose') 50 | ->willReturn(true); 51 | 52 | $ps = new SocketPost($socket); 53 | $response = $ps->submit(new RequestParameters("aid","AppSecretKey", "Ticket","Randstr","UserIP")); 54 | $this->assertEquals(SocketPost::BAD_RESPONSE, $response); 55 | } 56 | 57 | public function testSubmitBadRequest() 58 | { 59 | $socket = $this->getMock('\\TekinTCaptcha\\RequestMethod\\Socket', array('fsockopen')); 60 | $socket->expects($this->once()) 61 | ->method('fsockopen') 62 | ->willReturn(false); 63 | $ps = new SocketPost($socket); 64 | $response = $ps->submit(new RequestParameters("aid","AppSecretKey", "Ticket","Randstr","UserIP")); 65 | $this->assertEquals(SocketPost::BAD_REQUEST, $response); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/TekinTCaptcha/RequestMethod/SocketPost.php: -------------------------------------------------------------------------------- 1 | socket = $socket; 51 | } else { 52 | $this->socket = new Socket(); 53 | } 54 | } 55 | 56 | /** 57 | * Submit the POST request with the specified parameters. 58 | * 59 | * @param RequestParameters $params Request parameters 60 | * @return string Body of the TekinTCaptcha response 61 | */ 62 | public function submit(RequestParameters $params) 63 | { 64 | $errno = 0; 65 | $errstr = ''; 66 | 67 | if (false === $this->socket->fsockopen('ssl://' . self::RECAPTCHA_HOST, 443, $errno, $errstr, 30)) { 68 | return self::BAD_REQUEST; 69 | } 70 | 71 | $content = $params->toQueryString(); 72 | 73 | $request = "POST " . self::SITE_VERIFY_PATH . " HTTP/1.1\r\n"; 74 | $request .= "Host: " . self::RECAPTCHA_HOST . "\r\n"; 75 | $request .= "Content-Type: application/x-www-form-urlencoded\r\n"; 76 | $request .= "Content-length: " . strlen($content) . "\r\n"; 77 | $request .= "Connection: close\r\n\r\n"; 78 | $request .= $content . "\r\n\r\n"; 79 | 80 | $this->socket->fwrite($request); 81 | $rawResponse = ''; 82 | 83 | while (!$this->socket->feof()) { 84 | $rawResponse .= $this->socket->fgets(4096); 85 | } 86 | 87 | $this->socket->fclose(); 88 | 89 | if (0 !== strpos($rawResponse, 'HTTP/1.1 200 OK')) { 90 | return self::BAD_RESPONSE; 91 | } 92 | 93 | $parts = preg_split("#\n\s*\n#Uis", $rawResponse); 94 | 95 | return $parts[1]; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/TekinTCaptcha/TekinTCaptcha.php: -------------------------------------------------------------------------------- 1 | aid = $aid; 55 | $this->AppSecretKey = $AppSecretKey; 56 | 57 | if (!is_null($requestMethod)) { 58 | $this->requestMethod = $requestMethod; 59 | } else { 60 | $this->requestMethod = new RequestMethod\CurlGet(); 61 | } 62 | } 63 | 64 | /** 65 | * Calls the TekinTCaptcha siteverify API to verify whether the user passes 66 | * @param string $Ticket The value of Ticket in the submitted form. 67 | * @param string $Randstr The value of Randstr in the submitted form. 68 | * @param string $UserIP The end user's IP address. 69 | * @return Response Response from the service. 70 | */ 71 | public function verify($Ticket, $Randstr, $UserIP = null) 72 | { 73 | // Discard empty solution submissions 74 | if (empty($Ticket)) { 75 | $TekinTCaptchaResponse = new Response(false, array('missing-input-ticket')); 76 | return $TekinTCaptchaResponse; 77 | } 78 | if (empty($Randstr)) { 79 | $TekinTCaptchaResponse = new Response(false, array('missing-input-randstr')); 80 | return $TekinTCaptchaResponse; 81 | } 82 | 83 | $params = new RequestParameters($this->aid, $this->AppSecretKey, $Ticket, $Randstr, $UserIP); 84 | 85 | $rawResponse = $this->requestMethod->submit($params); 86 | 87 | return Response::fromJson($rawResponse); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/TekinTCaptcha/RequestParameters.php: -------------------------------------------------------------------------------- 1 | aid = $aid; 51 | $this->AppSecretKey = $AppSecretKey; 52 | $this->Ticket = $Ticket; 53 | $this->Randstr = $Randstr; 54 | if (is_null($UserIP)) { 55 | $this->UserIP = $this->getRealIp(); 56 | }else{ 57 | $this->UserIP = $UserIP; 58 | } 59 | 60 | } 61 | 62 | /** 63 | * Array representation. 64 | * 65 | * @return array Array formatted parameters. 66 | */ 67 | public function toArray() 68 | { 69 | 70 | $params = array('aid' => $this->aid, 'AppSecretKey' => $this->AppSecretKey, 'Ticket' => $this->Ticket, 'Randstr' => $this->Randstr, 'UserIP'=>$this->UserIP); 71 | 72 | return $params; 73 | } 74 | 75 | /** 76 | * Query string representation for HTTP request. 77 | * 78 | * @return string Query string formatted parameters. 79 | */ 80 | public function toQueryString() 81 | { 82 | return http_build_query($this->toArray()); 83 | // return http_build_query($this->toArray(), '', '&'); 84 | } 85 | 86 | /** 87 | * Gets the real ip. 88 | * @author (tekinIf you do not have keys already then visit 33 | 34 | https://007.qq.com to generate them. 35 | Edit this file and set the respective keys in $aid and 36 | $AppSecretKey. Reload the page after this.
37 | 42 |That's it. Everything is working. Go integrate this into your real project.
62 | 63 | 67 |The following error was returned: 69 | 70 | 错误代码:' .$resp->getErrMsg(). ' '; 72 | echo '返回状态码:'. $resp->getStatus() .' '; 73 | echo '恶意等级:'. $resp->getEvilLevel() .' '; 74 | ?> 75 |
76 |Check the error msg code reference blow
77 |
78 |
79 | 验证失败,查看并检查配置参数信息。错误信息 详细说明 错误信息 详细说明 OK 验证通过 cmd no match 验证码系统命令号不匹配 user code len error 验证码长度不匹配 uin no match 号码不匹配 captcha no match 验证码答案不匹配/Randstr参数不匹配 seq redirect 重定向验证 verify timeout 验证码签名超时 opt no vcode 操作使用pt免验证码校验错误 Sequnce repeat 验证码签名重放 diff 差别,验证错误 Sequnce invalid 验证码签名序列 captcha type not match 验证码类型与拉取时不一致 Cookie invalid 验证码cookie信息不合法 verify type error 验证类型错误 verify ip no match ip不匹配 invalid pkg 非法请求包 decrypt fail 验证码签名解密失败 bad visitor 策略拦截 appid no match 验证码强校验appid错误 system busy 系统内部错误 param err AppSecretKey参数校验错误