TeacLogin.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. namespace app\common\logic;
  3. use app\common\model\OfflineRechargeRecordModel;
  4. use app\common\model\OfflineRechargeVerifyModel;
  5. use app\common\model\ParametersModel;
  6. use app\common\model\ServersModel;
  7. use app\common\model\UserModel;
  8. use fast\Http;
  9. use fast\RechargeOrderType;
  10. use fast\RechargeStatus;
  11. use fast\RechargeType;
  12. use think\Cache;
  13. use think\Env;
  14. use think\Log;
  15. /**
  16. * Teac交易
  17. */
  18. class TeacLogin
  19. {
  20. /**
  21. * 根据哈希查看交易详情
  22. *
  23. * 此接口为抓取币安浏览器页面html代码而来
  24. * 访问地址:https://bscscan.com/tx/0x48351c4c215645f2404741343c9be17b0ce494d70a7dba1bf11d1f5c2311de57
  25. */
  26. public function getInfoByTransactionHash($tx_hash = '0x48351c4c215645f2404741343c9be17b0ce494d70a7dba1bf11d1f5c2311de57')
  27. {
  28. if(empty($tx_hash)){
  29. return _error('hash不能为空');
  30. }
  31. // 读取远程页面地址
  32. $url = "https://bscscan.com/tx/" . $tx_hash;
  33. dump($url);
  34. // 使用 file_get_contents 函数读取远程页面
  35. //$html = file_get_contents($url);
  36. $html = Http::get($url);
  37. if(empty($html)){
  38. return _error('bscscan.com访问失败');
  39. }
  40. // dump($html);
  41. $dom = new \DOMDocument();
  42. libxml_use_internal_errors(true);//关掉错误提醒
  43. $dom->loadHTML($html);
  44. libxml_clear_errors();
  45. $get_html_value = $dom->getElementById('spanTxHash');
  46. if(empty($get_html_value)){
  47. return _error('当前页面没找到hash');
  48. }
  49. $resp['hash'] = $get_html_value->nodeValue;
  50. //$get_html_value = '<a class="text-break me-2" href="/address/' . $this->contract_address . '">' . $this->contract_address . '</a>';
  51. //$get_html_value = '<a class="me-1" href="/token/' . $this->contract_address . '" target="_parent">BSC-USD</a>';
  52. $get_html_value = '<a data-highlight-value data-highlight-target="' . $this->contract_address . '" class="d-flex align-items-center gap-0.5" href="/token/' . $this->contract_address . '">';
  53. if (!(strstr($html, $get_html_value))) {
  54. Log::error('合约地址和配置信息不相符:' . $tx_hash);
  55. return _error('合约地址和配置信息不相符');
  56. }
  57. $xpath = new \DOMXPath($dom);
  58. $get_html_value = $xpath->query('//span[@class="badge bg-success bg-opacity-10 border border-success border-opacity-25 text-green-600 fw-medium text-start text-wrap py-1.5 px-2"]');
  59. if ($get_html_value->length > 0 && $get_html_value->item(0)->nodeValue == 'Success') {
  60. $resp['pay_status'] = 1;
  61. } else {
  62. return _error('交易失败');
  63. }
  64. $get_html_value = $xpath->query('//span[@class="me-1"]');
  65. if ($get_html_value->length > 0) {
  66. $amount = $get_html_value->item(1)->nodeValue;//所有 span class='me-1' 的元素中,第二个就是额度,超过1000会有 逗号分割
  67. $resp['amount'] = str_replace(',', "", $amount);
  68. } else {
  69. return _error('当前页面没找到交易额度');
  70. }
  71. $get_html_value = $dom->getElementById('chunk_decodeori_0_1');
  72. if(empty($get_html_value)){
  73. return _error('当前页面没找到from_address');
  74. }
  75. $resp['from_address'] = strtolower($get_html_value->nodeValue);//转小写
  76. $get_html_value = $dom->getElementById('chunk_decodeori_0_2');
  77. if(empty($get_html_value)){
  78. return _error('当前页面没找到to_address');
  79. }
  80. $resp['to_address'] = strtolower($get_html_value->nodeValue);
  81. return _success($resp);
  82. }
  83. /**
  84. * 根据钱包地址查询交易记录
  85. *
  86. * @$address 查询地址
  87. * @$from_to 是查询付款交易(from),还剩收款交易(to),默认from
  88. */
  89. public function getTransactionRecordsByAddress(string $from, string $to, int $start_block, int $end_block = 99999999)
  90. {
  91. if(empty($from) && empty($to)){
  92. return _error('钱包地址不能都为空');
  93. }
  94. $from = strtolower($from);
  95. $to = strtolower($to);
  96. $address = $from;
  97. if(empty($from)){
  98. $address =$to;
  99. }
  100. // 读取远程页面地址
  101. $url = "https://api.bscscan.com/api?module=account&action=tokentx&contractaddress=" . $this->contract_address;
  102. $url .= "&page=1&offset=10000&endblock=" . $end_block ."&apikey=" . $this->bsc_api_key;
  103. $url .= "&startblock=" . $start_block . "&address=" . $address;
  104. Log::log($url);
  105. $body = Http::get($url);
  106. if (empty($body)) {
  107. Log::log('api返回内容为空');
  108. return _error('api返回内容为空');
  109. }
  110. // 转成数组
  111. $rsArr = json_decode($body, true);
  112. if (empty($rsArr) || !is_array($rsArr)) {
  113. Log::log('api返回数据异常,json decode失败');
  114. return _error('api返回数据异常');
  115. }
  116. if ($rsArr['status'] != '1') {
  117. if($rsArr['message'] == 'No transactions found'){
  118. Log::log('无交易记录:' . $rsArr['message']);
  119. return _success();
  120. }
  121. Log::log('api返回status不为1,错误信息:' . $rsArr['message']);
  122. return _error('api返回status不为1,错误信息:' . $rsArr['message']);
  123. }
  124. return _success($success_arr);
  125. }
  126. /**
  127. * 获取哈希地址成功状态
  128. * @param $orderInfo
  129. * @return array|string
  130. */
  131. public function getHashStatus($tx_hash):array
  132. {
  133. if (empty($tx_hash)) {
  134. return _error('hash值不能为空');
  135. }
  136. $url = "https://api.bscscan.com/api?module=transaction&action=gettxreceiptstatus";
  137. $url .= "&apikey=" . $this->bsc_api_key;
  138. $url .= "&txhash=" . $tx_hash;
  139. $body = Http::get($url);
  140. if (empty($body)) {
  141. return _error('状态api返回内容为空');
  142. }
  143. // 转成数组
  144. $rsArr = json_decode($body, true);
  145. if (empty($rsArr) || !is_array($rsArr)) {
  146. return _error('状态api返回数据异常,json转换失败');
  147. }
  148. if ($rsArr['status'] != '1') {
  149. return _error('状态api返回status不为1,当前值为:' . $rsArr['status']);
  150. }
  151. if ($rsArr['result']['status'] != 1) {
  152. return _error('状态api返回result中的status不为1,当前值为:' . $rsArr['result']['status']);
  153. }
  154. return _success();
  155. }
  156. /**
  157. * 根据时间戳获取最近的区块高度
  158. * api接口返回数据格式
  159. * @param $orderInfo
  160. * @return array|string
  161. */
  162. public function getBlockNoByTime($time):array
  163. {
  164. if(!Cache::has('block_' . $time)){
  165. if (empty($time)) {
  166. return _error('时间戳不能为空');
  167. }
  168. //https://api.bscscan.com/api?module=block&action=getblocknobytime&timestamp=1601510400&closest=before&apikey=YourApiKeyToken
  169. $url = "https://api.bscscan.com/api?module=block&action=getblocknobytime&";
  170. $url .= "&closest=before";//closest 值还有个参数 after 控制返回接近时间戳之前还是之后的区块高度
  171. $url .= "&apikey=" . $this->bsc_api_key;
  172. $url .= "&timestamp=" . $time;
  173. dump($url);
  174. $body = Http::get($url);
  175. if (empty($body)) {
  176. return _error('获取区块高度api返回内容为空');
  177. }
  178. // 转成数组
  179. $rsArr = json_decode($body, true);
  180. if (empty($rsArr) || !is_array($rsArr)) {
  181. return _error('获取区块高度api返回数据异常,json转换失败');
  182. }
  183. if ($rsArr['status'] != '1') {
  184. return _error($rsArr['message'] . ' -- ' . $rsArr['result']);
  185. }
  186. Cache::set('block_' . $time, _success($rsArr['result']), 3600);
  187. }
  188. //获取开始预约前的区块高度
  189. return Cache::get('block_' . $time);
  190. }
  191. public function getBlcokNoByCache($time){
  192. if(!Cache::has('block')){
  193. $get_block = (new BscApi())->getBlockNoByTime($start_time);
  194. if($get_block['code'] == 0){
  195. Log::info($get_block['msg'] . date('Y-m-d H:i:s'));
  196. dump('获取区块高度有误');
  197. dump($get_block);
  198. return;
  199. }
  200. Cache::set('block', $get_block['data'], 3600);
  201. }
  202. //获取开始预约前的区块高度
  203. $start_block = Cache::get('block');
  204. }
  205. }