backend.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. <?php
  2. class backend{
  3. public function __construct($scraper){
  4. $this->scraper = $scraper;
  5. }
  6. /*
  7. Proxy stuff
  8. */
  9. public function get_ip($proxy_index_raw = null){
  10. $pool = constant("config::PROXY_" . strtoupper($this->scraper));
  11. if($pool === false){
  12. // we don't want a proxy, fuck off!
  13. return 'raw_ip::::';
  14. }
  15. // indent
  16. if($proxy_index_raw === null){
  17. $proxy_index_raw = apcu_inc("p." . $this->scraper);
  18. }
  19. $proxylist = file_get_contents("data/proxies/" . $pool . ".txt");
  20. $proxylist = explode("\n", $proxylist);
  21. // ignore empty or commented lines
  22. $proxylist = array_filter($proxylist, function($entry){
  23. $entry = ltrim($entry);
  24. return strlen($entry) > 0 && substr($entry, 0, 1) != "#";
  25. });
  26. $proxylist = array_values($proxylist);
  27. if(count($proxylist) === 0){
  28. throw new Exception("A proxy list was specified but it's empty!");
  29. }
  30. //echo $proxylist[$proxy_index_raw % count($proxylist)];
  31. return $proxylist[$proxy_index_raw % count($proxylist)];
  32. }
  33. // this function is also called directly on nextpage
  34. public function assign_proxy(&$curlproc, string $ip){
  35. // parse proxy line
  36. [
  37. $type,
  38. $address,
  39. $port,
  40. $username,
  41. $password
  42. ] = explode(":", $ip, 5);
  43. switch($type){
  44. case "raw_ip":
  45. return;
  46. break;
  47. case "http":
  48. case "https":
  49. curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
  50. curl_setopt($curlproc, CURLOPT_PROXY, $type . "://" . $address . ":" . $port);
  51. break;
  52. case "socks4":
  53. curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
  54. curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
  55. break;
  56. case "socks5":
  57. curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
  58. curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
  59. break;
  60. case "socks4a":
  61. curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A);
  62. curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
  63. break;
  64. case "socks5_hostname":
  65. case "socks5h":
  66. case "socks5a":
  67. curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
  68. curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
  69. break;
  70. }
  71. if($username != ""){
  72. curl_setopt($curlproc, CURLOPT_PROXYUSERPWD, $username . ":" . $password);
  73. }
  74. }
  75. // API key rotation
  76. public function get_key(){
  77. $keys = file_get_contents("data/api_keys/" . $this->scraper . ".txt");
  78. $keys = explode("\n", $keys);
  79. $keys = array_filter($keys, function($entry){
  80. $entry = ltrim($entry);
  81. return strlen($entry) > 0 && substr($entry, 0, 1) != "#";
  82. });
  83. $keys = array_values($keys);
  84. if(count($keys) === 0){
  85. throw new Exception("Please specify API keys in data/api_keys/" . $this->scraper . ".txt");
  86. }
  87. $increment = apcu_inc("s." . $this->scraper) % count($keys);
  88. return [
  89. "key" => $keys[$increment],
  90. "increment" => $increment
  91. ];
  92. }
  93. /*
  94. Next page stuff
  95. */
  96. public function store(string $payload, string $page, string $proxy){
  97. $key = sodium_crypto_secretbox_keygen();
  98. $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
  99. $requestid = apcu_inc("requestid");
  100. apcu_store(
  101. $page[0] . "." . // first letter of page name
  102. $this->scraper . // scraper name
  103. $requestid,
  104. [
  105. $nonce,
  106. $proxy,
  107. // compress and encrypt
  108. sodium_crypto_secretbox(
  109. gzdeflate($payload),
  110. $nonce,
  111. $key
  112. )
  113. ],
  114. 900 // cache information for 15 minutes
  115. );
  116. return
  117. $this->scraper . $requestid . "." .
  118. rtrim(strtr(base64_encode($key), '+/', '-_'), '=');
  119. }
  120. public function get(string $npt, string $page){
  121. $page = $page[0];
  122. $explode = explode(".", $npt, 2);
  123. if(count($explode) !== 2){
  124. throw new Exception("Malformed nextPageToken!");
  125. }
  126. $apcu = $page . "." . $explode[0];
  127. $key = $explode[1];
  128. $payload = apcu_fetch($apcu);
  129. if($payload === false){
  130. throw new Exception("The next page token is invalid or has expired!");
  131. }
  132. $key =
  133. base64_decode(
  134. str_pad(
  135. strtr($key, '-_', '+/'),
  136. strlen($key) % 4,
  137. '=',
  138. STR_PAD_RIGHT
  139. )
  140. );
  141. // decrypt and decompress data
  142. $payload[2] =
  143. gzinflate(
  144. sodium_crypto_secretbox_open(
  145. $payload[2], // data
  146. $payload[0], // nonce
  147. $key
  148. )
  149. );
  150. if($payload[2] === false){
  151. throw new Exception("The next page token is invalid or has expired!");
  152. }
  153. // remove the key after using successfully
  154. apcu_delete($apcu);
  155. return [
  156. $payload[2], // data
  157. $payload[1] // proxy
  158. ];
  159. }
  160. }