· 5 years ago · Jan 22, 2021, 07:02 AM
1<?php
2
3header('Access-Control-Allow-Origin: *');
4header('Content-Type: application/javascript');
5// Query params are:
6//require_once dirname(__FILE__) . '/kclick_client.php';
7$client = new KClickClient('http://94.140.114.223/api.php?', 'yPBDpvFPt6TcjwkB');
8$client->sendAllParams(); // to send all params from page query
9$client->forceRedirectOffer(); // redirect to offer if an offer is chosen
10// $client->param('sub_id_5', '123'); // you can send any params
11$client->param('frm', 'script'); // you can send any params
12// $client->keyword('PASTE_KEYWORD'); // send custom keyword
13// $client->currentPageAsReferrer(); // to send current page URL as click referrer
14// $client->debug(); // to enable debug mode and show the errors
15// $client->execute(); // request to api, show the output and continue
16$client->executeAndBreak(); // to stop page execution if there is redirect or some output
17
18
19
20/**
21 * Usage:
22 * require_once 'kclick_client.php';
23 * $client = new KClickClient('http://tds.com/api.php', 'CAMPAIGN_TOKEN');
24 * $client->sendUtmLabels(); # send only utm labels
25 * $client->sendAllParams(); # send all params
26 * $client
27 * ->keyword('[KEYWORD]')
28 * ->execute(); # use executeAndBreak() to break the page execution if there is redirect or some output
29 *
30 */
31class KClickClient
32{
33 const SESSION_SUB_ID = 'sub_id';
34 const SESSION_LANDING_TOKEN = 'landing_token';
35 /** @version 3.5 **/
36 const VERSION = 3;
37 const STATE_SESSION_KEY = 'keitaro_state';
38 const STATE_SESSION_EXPIRES_KEY = 'keitaro_state_expires';
39 const DEFAULT_TTL = 1;
40 /**
41 * @var KHttpClient
42 */
43 private $_httpClient;
44 private $_debug = false;
45 private $_trackerUrl;
46 private $_params = array();
47 private $_log = array();
48 private $_excludeParams = array('api_key', 'token', 'language', 'ua', 'ip', 'referrer', 'force_redirect_offer');
49 private $_result;
50 private $_stateRestored;
51
52 const ERROR = '[KTrafficClient] Something is wrong. Enable debug mode to see the reason.';
53
54 public function __construct($trackerUrl, $token)
55 {
56 $this->trackerUrl($trackerUrl);
57 $this->campaignToken($token);
58 $this->version(self::VERSION);
59 $this->param('info', 1);
60 $this->fillParams();
61 }
62
63 public function fillParams()
64 {
65 $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
66 $this->setHttpClient(new KHttpClient());
67
68 $this->ip($this->_findIp())
69 ->ua(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null)
70 ->language((isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2) : ''))
71 ->seReferrer($referrer)
72 ->referrer($referrer)
73 ->param('original_headers', getallheaders())
74 ->param('original_host', isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost')
75 ->param('kversion', '3.4');
76
77 if ($this->isPrefetchDetected()) {
78 $this->param('prefetch', 1);
79 }
80 }
81
82 public function currentPageAsReferrer()
83 {
84 $this->referrer($this->_getCurrentPage());
85 return $this;
86 }
87
88 public function debug($state = true)
89 {
90 $this->_debug = $state;
91 return $this;
92 }
93
94 public function seReferrer($seReferrer)
95 {
96 $this->_params['se_referrer'] = $seReferrer;
97 return $this;
98 }
99
100 public function referrer($referrer)
101 {
102 $this->_params['referrer'] = $referrer;
103 return $this;
104 }
105
106 public function setHttpClient($httpClient)
107 {
108 $this->_httpClient = $httpClient;
109 return $this;
110 }
111
112 public function trackerUrl($name)
113 {
114 $this->_trackerUrl = $name;
115 }
116
117 // @deprecated
118 public function token($token)
119 {
120 return $this->campaignToken($token);
121 }
122
123 public function campaignToken($campaignToken)
124 {
125 $this->_params['token'] = $campaignToken;
126 return $this;
127 }
128 public function version($version)
129 {
130 $this->_params['version'] = $version;
131 return $this;
132 }
133
134 public function ua($ua)
135 {
136 $this->_params['ua'] = $ua;
137 return $this;
138 }
139
140 public function language($language)
141 {
142 $this->_params['language'] = $language;
143 return $this;
144 }
145
146 public function keyword($keyword)
147 {
148 $this->_params['keyword'] = $keyword;
149 return $this;
150 }
151
152 public function forceRedirectOffer()
153 {
154 $this->_params['force_redirect_offer'] = 1;
155 }
156
157 public function ip($ip)
158 {
159 $this->_params['ip'] = $ip;
160 return $this;
161 }
162
163 public function sendUtmLabels()
164 {
165 foreach ($_GET as $name => $value) {
166 if (strstr($name, 'utm_')) {
167 $this->_params[$name] = $value;
168 }
169 }
170 }
171
172 public function setLandingToken($token)
173 {
174 $this->_startSession();
175 $_SESSION['token'] = $token;
176 }
177
178 public function getSubId()
179 {
180 $result = $this->performRequest();
181 if (empty($result->info->sub_id)) {
182 $this->log('No sub_id is defined');
183 return 'no_subid';
184 }
185 $subId = $result->info->sub_id;
186 return $subId;
187 }
188
189 public function getToken()
190 {
191 $result = $this->performRequest();
192 if (empty($result->info->sub_id)) {
193 $this->log('No landing token is defined');
194 return 'no_token';
195 }
196 $subId = $result->info->token;
197 return $subId;
198 }
199
200 public function sendAllParams()
201 {
202 foreach ($_GET as $name => $value) {
203 if (empty($this->_params[$name]) && !in_array($name, $this->_excludeParams)) {
204 $this->_params[$name] = $value;
205 }
206 }
207 }
208
209 public function restoreFromSession()
210 {
211 if ($this->isStateRestored()) {
212 return;
213 }
214 $this->_startSession();
215 if (!empty($_SESSION[self::STATE_SESSION_KEY])) {
216 if ($_SESSION[self::STATE_SESSION_EXPIRES_KEY] < time()) {
217 unset($_SESSION[self::STATE_SESSION_KEY]);
218 unset($_SESSION[self::STATE_SESSION_EXPIRES_KEY]);
219 $this->log('State expired');
220 } else {
221 $this->_result = json_decode($_SESSION[self::STATE_SESSION_KEY], false);
222 if (isset($this->_result) && isset($this->_result->headers)) {
223 $this->_result->headers = array();
224 }
225 $this->_stateRestored = true;
226 $this->log('State restored');
227 }
228 }
229 }
230
231 public function restoreFromQuery()
232 {
233 if (isset($_GET['_subid'])) {
234 $this->_stateRestored = true;
235 if (empty($this->_result)) {
236 $this->_result = new StdClass();
237 $this->_result->info = new StdClass();
238 }
239 $this->_result->info->sub_id = $_GET['_subid'];
240 $this->log('SubId loaded from query');
241 if (isset($_GET['_token'])) {
242 $this->_result->info->token = $_GET['_token'];
243 $this->log('Landing token loaded from query');
244 }
245 $this->_storeState($this->_result, self::DEFAULT_TTL);
246 $this->_stateRestored = true;
247 }
248 }
249
250 public function isStateRestored()
251 {
252 return $this->_stateRestored;
253 }
254
255 public function isPrefetchDetected()
256 {
257 $checkServerParams = array('HTTP_X_PURPOSE' => 'preview', 'HTTP_X_MOZ' => 'prefetch', 'HTTP_X_FB_HTTP_ENGINE' => 'Liger');
258 foreach ($checkServerParams as $name => $value) {
259 if (isset($_SERVER[$name]) && $_SERVER[$name] == $value) {
260 return true;
261 }
262 }
263 return false;
264 }
265
266 public function saveCookie($key, $value, $ttl)
267 {
268 if (isset($_COOKIE[$key]) && $_COOKIE[$key] == $value) {
269 return;
270 }
271 if (!headers_sent()) {
272 setcookie($key, $value, $this->_getCookiesExpireTimestamp($ttl), '/', $this->_getCookieHost());
273 }
274 $_COOKIE[$key] = $value;
275 }
276
277 public function param($name, $value)
278 {
279 if (!in_array($name, $this->_excludeParams)) {
280 $this->_params[$name] = $value;
281 }
282 return $this;
283 }
284
285 public function params($value)
286 {
287 if (!empty($value)) {
288 if (is_string($value)) {
289 parse_str($value, $result);
290 foreach ($result as $name => $value) {
291 $this->param($name, $value);
292 }
293 }
294 }
295
296 return $this;
297 }
298
299 public function reset()
300 {
301 $this->_result = null;
302 }
303
304 public function performRequest()
305 {
306 if ($this->_result) {
307 return $this->_result;
308 }
309 $request = $this->_buildRequestUrl();
310 $params = $this->getParams();
311 $options = $this->_getRequestOptions();
312 $this->log('Request: ' . $request);
313 try {
314 $result = $this->_httpClient->request($request, $params, $options);
315 $this->log('Response: ' . $result);
316 } catch (KTrafficClientError $e) {
317 if ($this->_debug) {
318 throw $e;
319 } else {
320 return self::ERROR;
321 }
322 }
323 $this->_result = json_decode($result);
324 $this->_storeState(
325 $this->_result,
326 isset($this->_result->cookies_ttl) ? $this->_result->cookies_ttl : null
327 );
328
329 if (isset($this->_result->cookies)) {
330 $this->_saveKeitaroCookies($this->_result->cookies , $this->_result->cookies_ttl);
331 }
332 return $this->_result;
333 }
334
335 public function execute($break = false, $print = true)
336 {
337 $content = $this->getContent();
338
339 if ($print) {
340 $headers = $this->sendHeaders();
341 echo $content;
342 } else {
343 return $content;
344 }
345
346 if ($break && (!empty($content) || $this->checkHeaders($headers))) {
347 exit;
348 }
349 }
350
351 public function checkHeaders($headers)
352 {
353 if (empty($headers)) {
354 return;
355 }
356 foreach ($headers as $header) {
357 if (strpos($header, 'Location:') === 0) {
358 return true;
359 }
360 if ($header == 'HTTP/1.1 404 Not Found') {
361 return true;
362 }
363 }
364 return false;
365 }
366
367 public function getContent()
368 {
369 $result = $this->performRequest();
370 $content = '';
371 if (!empty($result)) {
372 if (!empty($result->error)) {
373 $content .= $result->error;
374 }
375 if (!empty($result->body)) {
376 if (isset($result->contentType) && (strstr($result->contentType, 'image') || strstr($result->contentType, 'application/pdf'))) {
377 $content = base64_decode($result->body);
378 } else {
379 $content .= $result->body;
380 }
381 }
382 }
383
384 return $content;
385 }
386
387 public function showLog($separator = '<br />')
388 {
389 echo '<hr>' . implode($separator, $this->getLog()). '<hr>';
390 }
391
392 public function log($msg)
393 {
394 if ($this->_debug) {
395 error_log($msg);
396 }
397 $this->_log[] = $msg;
398 }
399
400 public function getLog()
401 {
402 return $this->_log;
403 }
404
405 public function executeAndBreak()
406 {
407 $this->execute(true);
408 }
409
410 public function getParams()
411 {
412 return $this->_params;
413 }
414
415 private function _storeState($result, $ttl)
416 {
417 $this->_startSession();
418 $_SESSION[self::STATE_SESSION_KEY] = json_encode($result);
419 $_SESSION[self::STATE_SESSION_EXPIRES_KEY] = time() + ($ttl * 60 * 60);
420
421 // for back-compatibility purpose
422 if (!empty($result->info)) {
423 if (!empty($result->info->sub_id)) {
424 $_SESSION[self::SESSION_SUB_ID] = $result->info->sub_id;
425 }
426 if (!empty($result->info->token)) {
427 $_SESSION[self::SESSION_LANDING_TOKEN] = $result->info->token;
428 }
429 }
430 }
431
432 private function _saveKeitaroCookies($cookies, $ttl)
433 {
434 foreach ($cookies as $key => $value) {
435 $this->saveCookie($key, $value, $ttl);
436 }
437 }
438
439 public function sendHeaders()
440 {
441 $result = $this->performRequest();
442 $headers = array();
443 $file = "";
444 $line = "";
445 if (headers_sent($file, $line)) {
446 $msg = "Body output already started";
447 if (!empty($file)) {
448 $msg .= "({$file}:{$line})";
449 }
450 $this->log($msg);
451 }
452
453
454 if (!empty($result->headers)) {
455 foreach ($result->headers as $header) {
456 $headers[] = $header;
457 if (!headers_sent()) {
458 header($header);
459 }
460 }
461 }
462
463 if (!empty($result->status)) {
464 http_response_code($result->status);
465 }
466
467 if (!empty($result->contentType)) {
468 $header = 'Content-Type: ' . $result->contentType;
469 $headers[] = $header;
470 if (!headers_sent()) {
471 header($header);
472 }
473 }
474 return $headers;
475 }
476
477 // @deprecated
478 public function updateHeaders()
479 {
480 $this->sendHeaders();
481 }
482
483 public function getOffer($params = array(), $fallback = 'no_offer')
484 {
485 $result = $this->performRequest();
486 $token = $this->getToken();
487 if (empty($token)) {
488 $this->log('Campaign hasn\'t returned offer');
489 return $fallback;
490 }
491 $params['_lp'] = 1;
492 $params['_token'] = $result->info->token;
493 return $this->_buildOfferUrl($params);
494 }
495
496 public function isBot()
497 {
498 $result = $this->performRequest();
499 if (isset($result->info)) {
500 return isset($result->info->is_bot) ? $result->info->is_bot : false;
501 }
502 }
503
504 public function isUnique($level = 'campaign')
505 {
506 $result = $this->performRequest();
507 if (isset($result->info) && $result->info->uniqueness) {
508 return isset($result->info->uniqueness->$level) ? $result->info->uniqueness->$level : false;
509 }
510 }
511
512 // @deprecated
513 public function forceChooseOffer()
514 {
515 throw new \Error('forceChooseOffer was removed in KClickClient v3.');
516 }
517
518 public function getBody()
519 {
520 $result = $this->performRequest();
521 return $result->body;
522 }
523
524 public function getHeaders()
525 {
526 $result = $this->performRequest();
527 return $result->headers;
528 }
529
530 private function _startSession()
531 {
532 if (!headers_sent()) {
533 @session_start();
534 }
535 }
536
537 private function _buildOfferUrl($params = array())
538 {
539 $request = parse_url($this->_trackerUrl);
540 $lastChar = substr($request['path'], -1);
541 if ($lastChar != '/' && $lastChar != '\\') {
542 $path = str_replace(basename($request['path']), '', $request['path']);
543 } else {
544 $path = $request['path'];
545 }
546 $path = ltrim($path, "\\\/");
547 $params = http_build_query($params);
548 return "{$request['scheme']}://{$request['host']}/{$path}?{$params}";
549 }
550
551
552 private function _getCurrentPage()
553 {
554 if ((isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) || !empty($_SERVER['HTTPS'])) {
555 $scheme = 'https';
556 } else {
557 $scheme = 'http';
558 }
559 return $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
560 }
561
562 private function _buildRequestUrl()
563 {
564 $request = parse_url($this->_trackerUrl);
565 $url = "{$request['scheme']}://{$request['host']}";
566 if (isset($request['port'])) {
567 $url = ':' . $request['port'];
568 }
569 $url .= "/{$request['path']}";
570 return $url;
571 }
572
573
574 private function _findIp()
575 {
576 $ip = null;
577 $headers = array(
578 'HTTP_X_FORWARDED_FOR',
579 'HTTP_FORWARDED_FOR',
580 'HTTP_X_FORWARDED',
581 'HTTP_FORWARDED',
582 'HTTP_CLIENT_IP',
583 'HTTP_FORWARDED_FOR_IP',
584 'X_FORWARDED_FOR',
585 'FORWARDED_FOR',
586 'X_FORWARDED',
587 'FORWARDED',
588 'CLIENT_IP',
589 'FORWARDED_FOR_IP',
590 'HTTP_PROXY_CONNECTION');
591 foreach ($headers as $header) {
592 if (!empty($_SERVER[$header])) {
593 $tmp = explode(',', $_SERVER[$header]);
594 $ip = trim($tmp[0]);
595 break;
596 }
597 }
598 if (strstr($ip, ',')) {
599 $tmp = explode(',', $ip);
600 if (stristr($_SERVER['HTTP_USER_AGENT'], 'mini')) {
601 $ip = trim($tmp[count($tmp) - 2]);
602 } else {
603 $ip = trim($tmp[0]);
604 }
605 }
606
607 if (empty($ip)) {
608 $ip = $_SERVER['REMOTE_ADDR'];
609 }
610
611 return $ip;
612 }
613
614 private function _getCookiesExpireTimestamp($ttl)
615 {
616 return time() + 60 * 60 * $ttl;
617 }
618
619 private function _getCookieHost()
620 {
621 if (isset($_SERVER['HTTP_HOST']) && substr_count($_SERVER['HTTP_HOST'], '.') < 3) {
622 $host = '.' . str_replace('www.', '', $_SERVER['HTTP_HOST']);
623 } else {
624 $host = null;
625 }
626 return $host;
627 }
628
629 private function _getRequestOptions()
630 {
631 $opts = array();
632 if (isset($_SERVER["HTTP_COOKIE"])) {
633 $opts['cookies'] = preg_replace('/PHPSESSID=.*?;/si', '', $_SERVER["HTTP_COOKIE"]);
634 }
635
636 return $opts;
637 }
638}
639
640class KHttpClient
641{
642 const UA = 'KHttpClient';
643
644 public function request($url, $params, $opts = array())
645 {
646 $ch = curl_init();
647 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
648 curl_setopt($ch, CURLOPT_URL, $url);
649 curl_setopt($ch, CURLOPT_HEADER, 0);
650 curl_setopt($ch, CURLOPT_COOKIE, isset($opts['cookies']) ? $opts['cookies'] : null);
651 curl_setopt($ch, CURLOPT_NOBODY, 0);
652 curl_setopt($ch, CURLOPT_TIMEOUT, 10);
653 curl_setopt($ch, CURLOPT_USERAGENT, self::UA);
654 curl_setopt($ch, CURLOPT_POST, 1);
655 curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
656 $result = curl_exec($ch);
657 if (curl_error($ch)) {
658 throw new KTrafficClientError(curl_error($ch));
659 }
660
661 if (empty($result)) {
662 throw new KTrafficClientError('Empty response');
663 }
664 return $result;
665 }
666}
667
668class KTrafficClientError extends \Exception {}
669
670
671if (!function_exists('http_response_code')) {
672 function http_response_code($code = NULL) {
673
674 if ($code !== NULL) {
675
676 switch ($code) {
677 case 100: $text = 'Continue'; break;
678 case 101: $text = 'Switching Protocols'; break;
679 case 200: $text = 'OK'; break;
680 case 201: $text = 'Created'; break;
681 case 202: $text = 'Accepted'; break;
682 case 203: $text = 'Non-Authoritative Information'; break;
683 case 204: $text = 'No Content'; break;
684 case 205: $text = 'Reset Content'; break;
685 case 206: $text = 'Partial Content'; break;
686 case 300: $text = 'Multiple Choices'; break;
687 case 301: $text = 'Moved Permanently'; break;
688 case 302: $text = 'Moved Temporarily'; break;
689 case 303: $text = 'See Other'; break;
690 case 304: $text = 'Not Modified'; break;
691 case 305: $text = 'Use Proxy'; break;
692 case 400: $text = 'Bad Request'; break;
693 case 401: $text = 'Unauthorized'; break;
694 case 402: $text = 'Payment Required'; break;
695 case 403: $text = 'Forbidden'; break;
696 case 404: $text = 'Not Found'; break;
697 case 405: $text = 'Method Not Allowed'; break;
698 case 406: $text = 'Not Acceptable'; break;
699 case 407: $text = 'Proxy Authentication Required'; break;
700 case 408: $text = 'Request Time-out'; break;
701 case 409: $text = 'Conflict'; break;
702 case 410: $text = 'Gone'; break;
703 case 411: $text = 'Length Required'; break;
704 case 412: $text = 'Precondition Failed'; break;
705 case 413: $text = 'Request Entity Too Large'; break;
706 case 414: $text = 'Request-URI Too Large'; break;
707 case 415: $text = 'Unsupported Media Type'; break;
708 case 500: $text = 'Internal Server Error'; break;
709 case 501: $text = 'Not Implemented'; break;
710 case 502: $text = 'Bad Gateway'; break;
711 case 503: $text = 'Service Unavailable'; break;
712 case 504: $text = 'Gateway Time-out'; break;
713 case 505: $text = 'HTTP Version not supported'; break;
714 default:
715 exit('Unknown http status code "' . htmlentities($code) . '"');
716 break;
717 }
718
719 $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
720
721 header($protocol . ' ' . $code . ' ' . $text);
722
723 $GLOBALS['http_response_code'] = $code;
724
725 } else {
726
727 $code = (isset($GLOBALS['http_response_code']) ? $GLOBALS['http_response_code'] : 200);
728
729 }
730
731 return $code;
732
733 }
734}
735
736if (!function_exists('getallheaders'))
737{
738 function getallheaders()
739 {
740 $headers = array();
741 foreach ($_SERVER as $name => $value)
742 {
743 if (substr($name, 0, 5) == 'HTTP_')
744 {
745 $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
746 }
747 }
748 return $headers;
749 }
750}
751;?>
752