├── 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 | 3 | 4 | 5 | ./tests/TekinTCaptcha 6 | 7 | 8 | 9 | 10 | 11 | ./src/TekinTCaptcha 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/TekinTCaptcha/RequestMethod/Curl.php: -------------------------------------------------------------------------------- 1 | =5.6" 14 | }, 15 | "require-dev": { 16 | "phpunit/phpunit": "^6.5" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "TekinTCaptcha\\": "src/TekinTCaptcha" 21 | } 22 | }, 23 | "extra": { 24 | "branch-alias": { 25 | "dev-master": "1.1.x-dev" 26 | } 27 | }, 28 | 29 | "repositories": { 30 | "packagist": { 31 | "type": "composer", 32 | "url": "https://packagist.phpcomposer.com" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/autoload.php: -------------------------------------------------------------------------------- 1 | markTestSkipped( 15 | 'The cURL extension is not available.' 16 | ); 17 | } 18 | } 19 | 20 | public function testSubmit() 21 | { 22 | $curl = $this->getMock('\\TekinTCaptcha\\RequestMethod\\Curl', 23 | array('init', 'setoptArray', 'exec', 'close')); 24 | $curl->expects($this->once()) 25 | ->method('init') 26 | ->willReturn(new \stdClass); 27 | $curl->expects($this->once()) 28 | ->method('setoptArray') 29 | ->willReturn(true); 30 | $curl->expects($this->once()) 31 | ->method('exec') 32 | ->willReturn('RESPONSEBODY'); 33 | $curl->expects($this->once()) 34 | ->method('close'); 35 | 36 | $pc = new CurlPost($curl); 37 | $response = $pc->submit(new RequestParameters("aid","AppSecretKey", "Ticket","Randstr","UserIP")); 38 | $this->assertEquals('RESPONSEBODY', $response); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/TekinTCaptcha/RequestParametersTest.php: -------------------------------------------------------------------------------- 1 | 'aid','AppSecretKey'=>'AppSecretKey','Ticket'=>'Ticket','Randstr'=>'Randstr','UserIP'=>'UserIP' 14 | ),array('aid','AppSecretKey', 'Ticket','Randstr','UserIP',array('aid'=>'aid','AppSecretKey'=>'AppSecretKey','Ticket'=>'Ticket','Randstr'=>'Randstr'),'aid=aid&AppSecretKey=AppSecretKey&Ticket=Ticket&Randstr=Randstr') 15 | )); 16 | } 17 | 18 | /** 19 | * @dataProvider provideValidData 20 | */ 21 | public function testToArray($aid, $AppSecretKey, $Ticket, $Randstr,$UserIP, $expectedArray, $expectedQuery) 22 | { 23 | $params = new RequestParameters($aid, $AppSecretKey, $Ticket, $Randstr,$UserIP); 24 | $this->assertEquals($params->toArray(), $expectedArray); 25 | } 26 | 27 | /** 28 | * @dataProvider provideValidData 29 | */ 30 | public function testToQueryString($aid, $AppSecretKey, $Ticket, $Randstr,$UserIP, $expectedArray, $expectedQuery) 31 | { 32 | $params = new RequestParameters($aid, $AppSecretKey, $Ticket, $Randstr,$UserIP); 33 | $this->assertEquals($params->toQueryString(), $expectedQuery); 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tekin TencentCAPTCHA Example 6 | 7 | 8 |

Complete the Tekin TencentCAPTCHA then submit the form.

9 |
10 |
11 | An example form 12 |

Example input A:

13 |

Example input B:

14 | 15 | 16 | 17 | 18 | 19 | 20 |

21 | 22 |

23 | 24 |
25 |
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 (tekin ) 89 | * @return boolean The real ip. 90 | */ 91 | public function getRealIp(){ 92 | $ip = false; 93 | if (!empty($_SERVER["HTTP_CLIENT_IP"])) { 94 | $ip = $_SERVER["HTTP_CLIENT_IP"]; 95 | } 96 | if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { 97 | $ips = explode(", ", $_SERVER['HTTP_X_FORWARDED_FOR']); 98 | if ($ip) { 99 | array_unshift($ips, $ip); 100 | $ip = false; 101 | } 102 | for ($i = 0; $i < count($ips); $i++) { 103 | if (!preg_match("/^(10|172\.16|192\.168)\./i", $ips[$i])) { 104 | $ip = $ips[$i]; 105 | break; 106 | } 107 | } 108 | } 109 | return ($ip ? $ip : $_SERVER['REMOTE_ADDR']); 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/TekinTCaptcha/Response.php: -------------------------------------------------------------------------------- 1 | success = $success; 82 | $this->msg = $msg; 83 | $this->status = $status; 84 | $this->evil_level = $evil_level; 85 | } 86 | 87 | /** 88 | * Is success? 89 | * 90 | * @return boolean 91 | */ 92 | public function isSuccess() 93 | { 94 | return $this->success; 95 | } 96 | 97 | /** 98 | * Get error codes. 99 | * 100 | * @return array 101 | */ 102 | public function getErrMsg() 103 | { 104 | return $this->msg; 105 | } 106 | 107 | /** 108 | * 状态码获取 109 | * 110 | * @return The status. 111 | */ 112 | public function getStatus() 113 | { 114 | return $this->status; 115 | } 116 | 117 | /** 118 | * Get evil_level. 119 | * 120 | * @return string 121 | */ 122 | public function getEvilLevel() 123 | { 124 | return $this->evil_level; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /tests/TekinTCaptcha/RequestMethod/PostTest.php: -------------------------------------------------------------------------------- 1 | parameters = new RequestParameters("aid","AppSecretKey", "Ticket","Randstr","UserIP"); 17 | } 18 | 19 | public function tearDown() 20 | { 21 | self::$assert = null; 22 | } 23 | 24 | public function testHTTPContextOptions() 25 | { 26 | $req = new Post(); 27 | self::$assert = array($this, "httpContextOptionsCallback"); 28 | $req->submit($this->parameters); 29 | $this->assertEquals(1, $this->runcount, "The assertion was ran"); 30 | } 31 | 32 | public function testSSLContextOptions() 33 | { 34 | $req = new Post(); 35 | self::$assert = array($this, "sslContextOptionsCallback"); 36 | $req->submit($this->parameters); 37 | $this->assertEquals(1, $this->runcount, "The assertion was ran"); 38 | } 39 | 40 | public function httpContextOptionsCallback(array $args) 41 | { 42 | $this->runcount++; 43 | $this->assertCommonOptions($args); 44 | 45 | $options = stream_context_get_options($args[2]); 46 | $this->assertArrayHasKey('http', $options); 47 | 48 | $this->assertArrayHasKey('method', $options['http']); 49 | $this->assertEquals("POST", $options['http']['method']); 50 | 51 | $this->assertArrayHasKey('content', $options['http']); 52 | $this->assertEquals($this->parameters->toQueryString(), $options['http']['content']); 53 | 54 | $this->assertArrayHasKey('header', $options['http']); 55 | $headers = array( 56 | "Content-type: application/x-www-form-urlencoded", 57 | ); 58 | foreach ($headers as $header) { 59 | $this->assertContains($header, $options['http']['header']); 60 | } 61 | } 62 | 63 | public function sslContextOptionsCallback(array $args) 64 | { 65 | $this->runcount++; 66 | $this->assertCommonOptions($args); 67 | 68 | $options = stream_context_get_options($args[2]); 69 | $this->assertArrayHasKey('http', $options); 70 | $this->assertArrayHasKey('verify_peer', $options['http']); 71 | $this->assertTrue($options['http']['verify_peer']); 72 | 73 | $key = version_compare(PHP_VERSION, "5.6.0", "<") ? "CN_name" : "peer_name"; 74 | 75 | $this->assertArrayHasKey($key, $options['http']); 76 | $this->assertEquals("www.yunnan.ws", $options['http'][$key]); 77 | } 78 | 79 | protected function assertCommonOptions(array $args) 80 | { 81 | $this->assertCount(3, $args); 82 | $this->assertStringStartsWith("https://ssl.captcha.qq.com/ticket/verify", $args[0]); 83 | $this->assertFalse($args[1]); 84 | $this->assertTrue(is_resource($args[2]), "The context options should be a resource"); 85 | } 86 | } 87 | 88 | function file_get_contents() 89 | { 90 | if (PostTest::$assert) { 91 | return call_user_func(PostTest::$assert, func_get_args()); 92 | } 93 | // Since we can't represent maxlen in userland... 94 | return call_user_func_array('file_get_contents', func_get_args()); 95 | } 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TekinTCaptcha PHP client library 2 | ## 基于Google PHP项目设计思想实现的腾讯滑动智能验证码实现PHP中间件。 3 | 4 | * Project page: http://tekin.yunnan.ws/TekinTCaptcha/ 5 | * Repository: https://github.com/tekintian/TekinTCaptcha 6 | * Version: 1.0.0 7 | 8 | ## Description 9 | 腾讯验证码, 腾讯防水墙, 验证码, 滑动验证码, 智能滑动验证码PHP扩展, TekinTCaptcha - A Client library for Tencent Captcha, a service that protect websites from spam and abuse. 10 | TekinTCaptcha is a free CAPTCHA service that protect websites from spam and abuse. 11 | 12 | This is Tencent Captcha code that provides plugins for third-party integration with TekinTCaptcha. 13 | 14 | 15 | 16 | ## Installation 17 | 18 | ### Composer (Recommended) 19 | 20 | [Composer](https://getcomposer.org/) is a widely used dependency manager for PHP 21 | packages. This TekinTCaptcha client is available on Packagist as 22 | [`tekintian/tekintcaptcha`](https://packagist.org/packages/tekintian/tekintcaptcha) and can be 23 | installed either by running the `composer require` command or adding the library 24 | to your `composer.json`. To enable Composer for you project, refer to the 25 | project's [Getting Started](https://getcomposer.org/doc/00-intro.md) 26 | documentation. 27 | 28 | To add this dependency using the command, run the following from within your 29 | project directory: 30 | ``` 31 | composer require tekintian/tekintcaptcha "~1.0" 32 | ``` 33 | 34 | Alternatively, add the dependency directly to your `composer.json` file: 35 | ```json 36 | "require": { 37 | "tekintian/tekintcaptcha": "~1.0" 38 | } 39 | ``` 40 | 41 | ### Direct download (no Composer) 42 | 43 | If you wish to install the library manually (i.e. without Composer), then you 44 | can use the links on the main project page to either clone the repo or download 45 | the [ZIP file](https://github.com/tekintian/TekinTCaptcha/archive/master.zip). For 46 | convenience, an autoloader script is provided in `src/autoload.php` which you 47 | can require into your script instead of Composer's `vendor/autoload.php`. For 48 | example: 49 | 50 | ```php 51 | require('/path/to/TekinTCaptcha/src/autoload.php'); 52 | $recaptcha = new \TekinTCaptcha\TekinTCaptcha($aid,$AppSecretKey); 53 | ``` 54 | 55 | The classes in the project are structured according to the 56 | [PSR-4](http://www.php-fig.org/psr/psr-4/) standard, so you may of course also 57 | use your own autoloader or require the needed files directly in your code. 58 | 59 | 60 | ## Usage 61 | First, register keys for your site at http://007.qq.com 62 | 63 | When your app receives a form submission containing the `Ticket, Randstr` 64 | field, you can verify it using: 65 | ```php 66 | verify($Ticket, $Randstr, $UserIP); 69 | if ($resp->isSuccess()) { 70 | // verified! 71 | // if Domain Name Validation turned off don't forget to check hostname field 72 | // if($resp->getStatus() === 1) { } 73 | } else { 74 | $errors = $resp->getErrMsg(); 75 | } 76 | ``` 77 | 78 | You can see an end-to-end working example in 79 | [examples/index.html](examples/index.html) 80 | [examples/login.php](examples/login.php) 81 | 82 | # thinkphp5 demo 83 | 84 | conposer require tekintian/tekintcaptcha 85 | 86 | ```php 87 | //腾讯验证码配置 for config.php / app.php 88 | 'tenncent_cpatcha' => [ 89 | 'aid' => '123456', 90 | 'app_secret_key' => 'aaaaadfasdfdsfsdf**', 91 | ] 92 | 93 | //for login.php 94 | public function login() 95 | { 96 | // 指定模板输出 97 | return $this->fetch('login'); 98 | } 99 | public function doLogin(){ 100 | $post = input('param.'); // 获取全部参数 101 | if (isset($post['Ticket']) && $post['Ticket'] !='' ) { 102 | /*从tp5的配置文件中读取aid, AppSecretKey */ 103 | $aid=config('app.tenncent_cpatcha.aid'); 104 | $AppSecretKey=config('app.tenncent_cpatcha.app_secret_key'); 105 | /*实例化 TekinTCaptcha */ 106 | $captcha = new \TekinTCaptcha\TekinTCaptcha($aid,$AppSecretKey); 107 | /*验证票据*/ 108 | $resp = $captcha->verify($post['Ticket'], $post['Randstr']); 109 | 110 | if ($resp->isSuccess()){ 111 | //验证成功 112 | pp($post); 113 | 114 | //验证成功end 115 | }else{ 116 | foreach ($resp->getErrMsg() as $msg) { 117 | echo '' , $msg , ' '; 118 | } 119 | echo '返回状态码:'. $resp->getStatus() .' '; 120 | echo '恶意等级:'. $resp->getEvilLevel() .' '; 121 | } 122 | 123 | } 124 | 125 | } 126 | ``` 127 | 128 | # 打赏赞助 Donate 129 | ![Donate with alipay](alipay_donate.jpg "支付宝打赏赞助, Donate with Alipay") -------------------------------------------------------------------------------- /examples/login.php: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | TekinTCaptcha Example 17 | 27 | 28 | 29 |

TekinTCaptcha Example

30 | 31 |

Add your keys

32 |

If 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 |

POST data

43 |
44 | verify($_POST['Ticket'], $_POST['Randstr']); 56 | 57 | if ($resp->isSuccess()): 58 | // If the response is a success, that's it! 59 | ?> 60 |

Success!

61 |

That's it. Everything is working. Go integrate this into your real project.

62 |

Try again

63 | 67 |

Something went wrong

68 |

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 |
错误信息 详细说明 错误信息 详细说明
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参数校验错误
78 | 79 |
验证失败,查看并检查配置参数信息。

80 |

Try again

81 | 82 | 83 | 84 | 85 | --------------------------------------------------------------------------------