You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

311 regels
8.6 KiB

  1. <?php
  2. namespace common\service\geetest;
  3. use common\util\Util;
  4. /**
  5. * 极验行为式验证安全平台,php 网站主后台包含的库文件
  6. *
  7. * @author Tanxu
  8. */
  9. class GeetestService
  10. {
  11. const GT_SDK_VERSION = 'php_3.0.0';
  12. public static $connectTimeout = 1;
  13. public static $socketTimeout = 1;
  14. private $response;
  15. public function __construct()
  16. {
  17. $siteConfig = Util::getSiteConfig();
  18. $captcha_id = $siteConfig['geetest']['id'];
  19. $private_key = $siteConfig['geetest']['key'];
  20. $this->captcha_id = $captcha_id;
  21. $this->private_key = $private_key;
  22. }
  23. /**
  24. * 判断极验服务器是否down机
  25. *
  26. * @param array $data
  27. * @return int
  28. */
  29. public function pre_process($param, $new_captcha = 1)
  30. {
  31. $data = array('gt' => $this->captcha_id,
  32. 'new_captcha' => $new_captcha
  33. );
  34. $data = array_merge($data, $param);
  35. $query = http_build_query($data);
  36. $url = "http://api.geetest.com/register.php?" . $query;
  37. $challenge = $this->send_request($url);
  38. if (strlen($challenge) != 32) {
  39. $this->failback_process();
  40. return 0;
  41. }
  42. $this->success_process($challenge);
  43. return 1;
  44. }
  45. /**
  46. * @param $challenge
  47. */
  48. private function success_process($challenge)
  49. {
  50. $challenge = md5($challenge . $this->private_key);
  51. $result = array(
  52. 'success' => 1,
  53. 'gt' => $this->captcha_id,
  54. 'challenge' => $challenge,
  55. 'new_captcha' => 1
  56. );
  57. $this->response = $result;
  58. }
  59. /**
  60. *
  61. */
  62. private function failback_process()
  63. {
  64. $rnd1 = md5(rand(0, 100));
  65. $rnd2 = md5(rand(0, 100));
  66. $challenge = $rnd1 . substr($rnd2, 0, 2);
  67. $result = array(
  68. 'success' => 0,
  69. 'gt' => $this->captcha_id,
  70. 'challenge' => $challenge,
  71. 'new_captcha' => 1
  72. );
  73. $this->response = $result;
  74. }
  75. /**
  76. * @return mixed
  77. */
  78. public function get_response_str()
  79. {
  80. return json_encode($this->response);
  81. }
  82. /**
  83. * 返回数组方便扩展
  84. *
  85. * @return mixed
  86. */
  87. public function get_response()
  88. {
  89. return $this->response;
  90. }
  91. /**
  92. * 正常模式获取验证结果
  93. *
  94. * @param string $challenge
  95. * @param string $validate
  96. * @param string $seccode
  97. * @param array $param
  98. * @return int
  99. */
  100. public function success_validate($challenge, $validate, $seccode, $param, $json_format = 1)
  101. {
  102. if (!$this->check_validate($challenge, $validate)) {
  103. return 0;
  104. }
  105. $query = array(
  106. "seccode" => $seccode,
  107. "timestamp" => time(),
  108. "challenge" => $challenge,
  109. "captchaid" => $this->captcha_id,
  110. "json_format" => $json_format,
  111. "sdk" => self::GT_SDK_VERSION
  112. );
  113. $query = array_merge($query, $param);
  114. $url = "http://api.geetest.com/validate.php";
  115. $codevalidate = $this->post_request($url, $query);
  116. $obj = json_decode($codevalidate, true);
  117. if ($obj === false) {
  118. return 0;
  119. }
  120. if ($obj['seccode'] == md5($seccode)) {
  121. return 1;
  122. } else {
  123. return 0;
  124. }
  125. }
  126. /**
  127. * 宕机模式获取验证结果
  128. *
  129. * @param $challenge
  130. * @param $validate
  131. * @param $seccode
  132. * @return int
  133. */
  134. public function fail_validate($challenge, $validate, $seccode)
  135. {
  136. if (md5($challenge) == $validate) {
  137. return 1;
  138. } else {
  139. return 0;
  140. }
  141. }
  142. /**
  143. * @param $challenge
  144. * @param $validate
  145. * @return bool
  146. */
  147. private function check_validate($challenge, $validate)
  148. {
  149. if (strlen($validate) != 32) {
  150. return false;
  151. }
  152. if (md5($this->private_key . 'geetest' . $challenge) != $validate) {
  153. return false;
  154. }
  155. return true;
  156. }
  157. /**
  158. * GET 请求
  159. *
  160. * @param $url
  161. * @return mixed|string
  162. */
  163. private function send_request($url)
  164. {
  165. if (function_exists('curl_exec')) {
  166. $ch = curl_init();
  167. curl_setopt($ch, CURLOPT_URL, $url);
  168. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::$connectTimeout);
  169. curl_setopt($ch, CURLOPT_TIMEOUT, self::$socketTimeout);
  170. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  171. $curl_errno = curl_errno($ch);
  172. $data = curl_exec($ch);
  173. curl_close($ch);
  174. if ($curl_errno > 0) {
  175. return 0;
  176. } else {
  177. return $data;
  178. }
  179. } else {
  180. $opts = array(
  181. 'http' => array(
  182. 'method' => "GET",
  183. 'timeout' => self::$connectTimeout + self::$socketTimeout,
  184. )
  185. );
  186. $context = stream_context_create($opts);
  187. $data = @file_get_contents($url, false, $context);
  188. if ($data) {
  189. return $data;
  190. } else {
  191. return 0;
  192. }
  193. }
  194. }
  195. /**
  196. *
  197. * @param $url
  198. * @param array $postdata
  199. * @return mixed|string
  200. */
  201. private function post_request($url, $postdata = '')
  202. {
  203. if (!$postdata) {
  204. return false;
  205. }
  206. $data = http_build_query($postdata);
  207. if (function_exists('curl_exec')) {
  208. $ch = curl_init();
  209. curl_setopt($ch, CURLOPT_URL, $url);
  210. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  211. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::$connectTimeout);
  212. curl_setopt($ch, CURLOPT_TIMEOUT, self::$socketTimeout);
  213. //不可能执行到的代码
  214. if (!$postdata) {
  215. curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
  216. } else {
  217. curl_setopt($ch, CURLOPT_POST, 1);
  218. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  219. }
  220. $data = curl_exec($ch);
  221. if (curl_errno($ch)) {
  222. $err = sprintf("curl[%s] error[%s]", $url, curl_errno($ch) . ':' . curl_error($ch));
  223. $this->triggerError($err);
  224. }
  225. curl_close($ch);
  226. } else {
  227. if ($postdata) {
  228. $opts = array(
  229. 'http' => array(
  230. 'method' => 'POST',
  231. 'header' => "Content-type: application/x-www-form-urlencoded\r\n" . "Content-Length: " . strlen($data) . "\r\n",
  232. 'content' => $data,
  233. 'timeout' => self::$connectTimeout + self::$socketTimeout
  234. )
  235. );
  236. $context = stream_context_create($opts);
  237. $data = file_get_contents($url, false, $context);
  238. }
  239. }
  240. return $data;
  241. }
  242. /**
  243. * @param $err
  244. */
  245. private function triggerError($err)
  246. {
  247. trigger_error($err);
  248. }
  249. /**
  250. * Des:
  251. * Name: checkGee
  252. * @param $geetest_challenge
  253. * @param $geetest_validate
  254. * @param $geetest_seccode
  255. * @return array
  256. * @author 倪宗锋
  257. */
  258. public function checkGee($geetest_challenge, $geetest_validate, $geetest_seccode)
  259. {
  260. if (empty($geetest_challenge) || empty($geetest_validate) || empty($geetest_seccode)) {
  261. return Util::returnArrEr('请先完成验证!');
  262. }
  263. session_start();
  264. $data = array(
  265. "user_id" => $_SESSION['user_id'], # 网站用户id
  266. "client_type" => "web", #web:电脑上的浏览器;h5:手机上的浏览器,包括移动应用内完全内置的web_view;native:通过原生SDK植入APP应用的方式
  267. "ip_address" => "127.0.0.1" # 请在此处传输用户请求验证时所携带的IP
  268. );
  269. if ($_SESSION['gtserver'] == 1) { //服务器正常
  270. $result = $this->success_validate($geetest_challenge, $geetest_validate, $geetest_seccode, $data);
  271. if ($result) {
  272. return Util::returnArrSu();
  273. } else {
  274. return Util::returnArrEr('请先完成验证!');
  275. }
  276. } else { //服务器宕机,走failback模式
  277. if ($this->fail_validate($_POST['geetest_challenge'], $_POST['geetest_validate'], $_POST['geetest_seccode'])) {
  278. return Util::returnArrSu();
  279. } else {
  280. return Util::returnArrEr('请先完成验证!');
  281. }
  282. }
  283. }
  284. }