You are here

class Cleantalk in Anti Spam by CleanTalk 7.2

Same name and namespace in other branches
  1. 7.5 src/Cleantalk.php \Cleantalk
  2. 7 cleantalk.module \Cleantalk
  3. 7.4 src/Cleantalk.php \Cleantalk

Cleantalk class create request

Hierarchy

Expanded class hierarchy of Cleantalk

File

./cleantalk.module, line 522
Main CleanTalk integration module functions.

View source
class Cleantalk {

  /**
   * Debug level
   * @var int
   */
  public $debug = 0;

  /**
   * Maximum data size in bytes
   * @var int
   */
  private $dataMaxSise = 32768;

  /**
   * Data compression rate
   * @var int
   */
  private $compressRate = 6;

  /**
   * Server connection timeout in seconds
   * @var int
   */
  private $server_timeout = 3;

  /**
   * Cleantalk server url
   * @var string
   */
  public $server_url = null;

  /**
   * Last work url
   * @var string
   */
  public $work_url = null;

  /**
   * WOrk url ttl
   * @var int
   */
  public $server_ttl = null;

  /**
   * Time wotk_url changer
   * @var int
   */
  public $server_changed = null;

  /**
   * Flag is change server url
   * @var bool
   */
  public $server_change = false;

  /**
   * Use TRUE when need stay on server. Example: send feedback
   * @var bool
   */
  public $stay_on_server = false;

  /**
   * Codepage of the data
   * @var bool
   */
  public $data_codepage = null;

  /**
   * API version to use
   * @var string
   */
  public $api_version = '/api2.0';

  /**
   * Use https connection to servers
   * @var bool
   */
  public $ssl_on = false;

  /**
   * Minimal server response in miliseconds to catch the server
   *
   */
  public $min_server_timeout = 50;

  /**
   * Function checks whether it is possible to publish the message
   * @param CleantalkRequest $request
   * @return type
   */
  public function isAllowMessage(CleantalkRequest $request) {
    $this
      ->filterRequest($request);
    $msg = $this
      ->createMsg('check_message', $request);
    return $this
      ->httpRequest($msg);
  }

  /**
   * Function checks whether it is possible to publish the message
   * @param CleantalkRequest $request
   * @return type
   */
  public function isAllowUser(CleantalkRequest $request) {
    $this
      ->filterRequest($request);
    $msg = $this
      ->createMsg('check_newuser', $request);
    return $this
      ->httpRequest($msg);
  }

  /**
   * Function sends the results of manual moderation
   *
   * @param CleantalkRequest $request
   * @return type
   */
  public function sendFeedback(CleantalkRequest $request) {
    $this
      ->filterRequest($request);
    $msg = $this
      ->createMsg('send_feedback', $request);
    return $this
      ->httpRequest($msg);
  }

  /**
   *  Filter request params
   * @param CleantalkRequest $request
   * @return type
   */
  private function filterRequest(CleantalkRequest &$request) {

    // general and optional
    foreach ($request as $param => $value) {
      if (in_array($param, array(
        'message',
        'example',
        'agent',
        'sender_info',
        'sender_nickname',
        'post_info',
        'phone',
      )) && !empty($value)) {
        if (!is_string($value) && !is_integer($value)) {
          $request->{$param} = NULL;
        }
      }
      if (in_array($param, array(
        'stoplist_check',
        'allow_links',
      )) && !empty($value)) {
        if (!in_array($value, array(
          1,
          2,
        ))) {
          $request->{$param} = NULL;
        }
      }
      if (in_array($param, array(
        'js_on',
      )) && !empty($value)) {
        if (!is_integer($value)) {
          $request->{$param} = NULL;
        }
      }
      if ($param == 'sender_ip' && !empty($value)) {
        if (!is_string($value)) {
          $request->{$param} = NULL;
        }
      }
      if ($param == 'sender_email' && !empty($value)) {
        if (!is_string($value)) {
          $request->{$param} = NULL;
        }
      }
      if ($param == 'submit_time' && !empty($value)) {
        if (!is_int($value)) {
          $request->{$param} = NULL;
        }
      }
    }
  }

  /**
   * Compress data and encode to base64
   * @param type string
   * @return string
   */
  private function compressData($data = null) {
    if (strlen($data) > $this->dataMaxSise && function_exists('gzencode') && function_exists('base64_encode')) {
      $localData = gzencode($data, $this->compressRate, FORCE_GZIP);
      if ($localData === false) {
        return $data;
      }
      $localData = base64_encode($localData);
      if ($localData === false) {
        return $data;
      }
      return $localData;
    }
    return $data;
  }

  /**
   * Create msg for cleantalk server
   * @param type $method
   * @param CleantalkRequest $request
   * @return \xmlrpcmsg
   */
  private function createMsg($method, CleantalkRequest $request) {
    switch ($method) {
      case 'check_message':

        // Convert strings to UTF8
        $request->message = $this
          ->stringToUTF8($request->message, $this->data_codepage);
        $request->example = $this
          ->stringToUTF8($request->example, $this->data_codepage);
        $request->sender_email = $this
          ->stringToUTF8($request->sender_email, $this->data_codepage);
        $request->sender_nickname = $this
          ->stringToUTF8($request->sender_nickname, $this->data_codepage);
        $request->message = $this
          ->compressData($request->message);
        $request->example = $this
          ->compressData($request->example);
        break;
      case 'check_newuser':

        // Convert strings to UTF8
        $request->sender_email = $this
          ->stringToUTF8($request->sender_email, $this->data_codepage);
        $request->sender_nickname = $this
          ->stringToUTF8($request->sender_nickname, $this->data_codepage);
        break;
      case 'send_feedback':
        if (is_array($request->feedback)) {
          $request->feedback = implode(';', $request->feedback);
        }
        break;
    }
    $request->method_name = $method;

    //
    // Removing non UTF8 characters from request, because non UTF8 or malformed characters break json_encode().
    //
    foreach ($request as $param => $value) {
      if (!preg_match('//u', $value)) {
        $request->{$param} = 'Nulled. Not UTF8 encoded or malformed.';
      }
    }
    return $request;
  }

  /**
   * Send JSON request to servers
   * @param $msg
   * @return boolean|\CleantalkResponse
   */
  private function sendRequest($data = null, $url, $server_timeout = 3) {

    // Convert to array
    $data = drupal_json_decode(drupal_json_encode($data));

    // Convert to JSON
    $data = drupal_json_encode($data);
    if (isset($this->api_version)) {
      $url = $url . $this->api_version;
    }

    // Switching to secure connection
    if ($this->ssl_on && !preg_match("/^https:/", $url)) {
      $url = preg_replace("/^(http)/i", "\$1s", $url);
    }
    $result = false;
    $curl_error = null;
    if (function_exists('curl_init')) {
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_TIMEOUT, $server_timeout);
      curl_setopt($ch, CURLOPT_POST, 1);
      curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

      // receive server response ...
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

      // resolve 'Expect: 100-continue' issue
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Expect:',
      ));

      // see http://stackoverflow.com/a/23322368
      curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);

      // Disabling CA cert verivication
      // Disabling common name verification
      if ($this->ssl_on) {
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
      }
      $result = curl_exec($ch);
      if (!$result) {
        $curl_error = curl_error($ch);
      }
      curl_close($ch);
    }
    if (!$result) {
      $allow_url_fopen = ini_get('allow_url_fopen');
      if (function_exists('file_get_contents') && isset($allow_url_fopen) && $allow_url_fopen == '1') {
        $opts = array(
          'http' => array(
            'method' => 'POST',
            'header' => "Content-Type: text/html\r\n",
            'content' => $data,
            'timeout' => $server_timeout,
          ),
        );
        $context = stream_context_create($opts);
        $result = @file_get_contents($url, false, $context);
      }
    }
    if (!$result) {
      $response = null;
      $response['errno'] = 1;
      if ($curl_error) {
        $response['errstr'] = sprintf("CURL error: '%s'", $curl_error);
      }
      else {
        $response['errstr'] = 'No CURL support compiled in';
      }
      $response['errstr'] .= ' or disabled allow_url_fopen in php.ini.';
      $response = (object) drupal_json_decode(drupal_json_encode($response));
      return $response;
    }
    $errstr = null;
    $response = (object) drupal_json_decode($result);
    if ($result !== false && is_object($response)) {
      $response->errno = 0;
      $response->errstr = $errstr;
    }
    else {
      $errstr = 'Unknown response from ' . $url . '.' . ' ' . $result;
      $response = null;
      $response['errno'] = 1;
      $response['errstr'] = $errstr;
      $response = (object) drupal_json_decode(drupal_json_encode($response));
    }
    return $response;
  }

  /**
   * httpRequest
   * @param $msg
   * @return boolean|\CleantalkResponse
   */
  private function httpRequest($msg) {
    $result = false;
    $msg->all_headers = drupal_json_encode(apache_request_headers());

    //$msg->remote_addr=$_SERVER['REMOTE_ADDR'];

    //$msg->sender_info['remote_addr']=$_SERVER['REMOTE_ADDR'];
    $si = drupal_json_decode($msg->sender_info);
    $si['remote_addr'] = $_SERVER['REMOTE_ADDR'];
    $msg->sender_info = drupal_json_encode($si);
    if (isset($this->work_url) && $this->work_url !== '' && $this->server_changed + $this->server_ttl > time() || $this->stay_on_server == true) {
      $url = !empty($this->work_url) ? $this->work_url : $this->server_url;
      $result = $this
        ->sendRequest($msg, $url, $this->server_timeout);
    }
    if (($result === false || $result->errno != 0) && $this->stay_on_server == false) {

      // Split server url to parts
      preg_match("@^(https?://)([^/:]+)(.*)@i", $this->server_url, $matches);
      $url_prefix = '';
      if (isset($matches[1])) {
        $url_prefix = $matches[1];
      }
      $pool = null;
      if (isset($matches[2])) {
        $pool = $matches[2];
      }
      $url_suffix = '';
      if (isset($matches[3])) {
        $url_suffix = $matches[3];
      }
      if ($url_prefix === '') {
        $url_prefix = 'http://';
      }
      if (empty($pool)) {
        return false;
      }
      else {

        // Loop until find work server
        foreach ($this
          ->get_servers_ip($pool) as $server) {
          if ($server['host'] === 'localhost' || $server['ip'] === null) {
            $work_url = $server['host'];
          }
          else {
            $server_host = $server['ip'];
            $work_url = $server_host;
          }
          $work_url = $url_prefix . $work_url;
          if (isset($url_suffix)) {
            $work_url = $work_url . $url_suffix;
          }
          $this->work_url = $work_url;
          $this->server_ttl = $server['ttl'];
          $result = $this
            ->sendRequest($msg, $this->work_url, $this->server_timeout);
          if ($result !== false && $result->errno === 0) {
            $this->server_change = true;
            break;
          }
        }
      }
    }
    $response = new CleantalkResponse(null, $result);
    if (!empty($this->data_codepage) && $this->data_codepage !== 'UTF-8') {
      if (!empty($response->comment)) {
        $response->comment = $this
          ->stringFromUTF8($response->comment, $this->data_codepage);
      }
      if (!empty($response->errstr)) {
        $response->errstr = $this
          ->stringFromUTF8($response->errstr, $this->data_codepage);
      }
      if (!empty($response->sms_error_text)) {
        $response->sms_error_text = $this
          ->stringFromUTF8($response->sms_error_text, $this->data_codepage);
      }
    }
    return $response;
  }

  /**
   * Function DNS request
   * @param $host
   * @return array
   */
  public function get_servers_ip($host) {
    $response = null;
    if (!isset($host)) {
      return $response;
    }
    if (function_exists('dns_get_record')) {
      $records = dns_get_record($host, DNS_A);
      if ($records !== FALSE) {
        foreach ($records as $server) {
          $response[] = $server;
        }
      }
    }
    if (count($response) == 0 && function_exists('gethostbynamel')) {
      $records = gethostbynamel($host);
      if ($records !== FALSE) {
        foreach ($records as $server) {
          $response[] = array(
            "ip" => $server,
            "host" => $host,
            "ttl" => $this->server_ttl,
          );
        }
      }
    }
    if (count($response) == 0) {
      $response[] = array(
        "ip" => null,
        "host" => $host,
        "ttl" => $this->server_ttl,
      );
    }
    else {

      // $i - to resolve collisions with localhost
      $i = 0;
      $r_temp = null;
      $fast_server_found = false;
      foreach ($response as $server) {

        // Do not test servers because fast work server found
        if ($fast_server_found) {
          $ping = $this->min_server_timeout;
        }
        else {
          $ping = $this
            ->httpPing($server['ip']);
          $ping = $ping * 1000;
        }

        // -1 server is down, skips not reachable server
        if ($ping != -1) {
          $r_temp[$ping + $i] = $server;
        }
        $i++;
        if ($ping < $this->min_server_timeout) {
          $fast_server_found = true;
        }
      }
      if (count($r_temp)) {
        ksort($r_temp);
        $response = $r_temp;
      }
    }
    return $response;
  }

  /**
   * Function to get the message hash from Cleantalk.ru comment
   * @param $message
   * @return null
   */
  public function getCleantalkCommentHash($message) {
    $matches = array();
    if (preg_match('/\\n\\n\\*\\*\\*.+([a-z0-9]{32}).+\\*\\*\\*$/', $message, $matches)) {
      return $matches[1];
    }
    else {
      if (preg_match('/\\<br.*\\>[\\n]{0,1}\\<br.*\\>[\\n]{0,1}\\*\\*\\*.+([a-z0-9]{32}).+\\*\\*\\*$/', $message, $matches)) {
        return $matches[1];
      }
    }
    return NULL;
  }

  /**
   * Function adds to the post comment Cleantalk.ru
   * @param $message
   * @param $comment
   * @return string
   */
  public function addCleantalkComment($message, $comment) {
    $comment = preg_match('/\\*\\*\\*(.+)\\*\\*\\*/', $comment, $matches) ? $comment : '*** ' . $comment . ' ***';
    return $message . "\n\n" . $comment;
  }

  /**
   * Function deletes the comment Cleantalk.ru
   * @param $message
   * @return mixed
   */
  public function delCleantalkComment($message) {
    $message = preg_replace('/\\n\\n\\*\\*\\*.+\\*\\*\\*$/', '', $message);

    // DLE sign cut
    $message = preg_replace('/<br\\s?\\/><br\\s?\\/>\\*\\*\\*.+\\*\\*\\*$/', '', $message);
    $message = preg_replace('/\\<br.*\\>[\\n]{0,1}\\<br.*\\>[\\n]{0,1}\\*\\*\\*.+\\*\\*\\*$/', '', $message);
    return $message;
  }

  /**
   *   Get user IP behind proxy server
   */
  public function ct_session_ip($data_ip) {
    if (!$data_ip || !preg_match("/^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\$/", $data_ip)) {
      return $data_ip;
    }

    /*if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {

                $forwarded_ip = explode(",", $_SERVER['HTTP_X_FORWARDED_FOR']);

                // Looking for first value in the list, it should be sender real IP address
                if (!preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $forwarded_ip[0])) {
                    return $data_ip;
                }

                $private_src_ip = false;
                $private_nets = array(
                    '10.0.0.0/8',
                    '127.0.0.0/8',
                    '176.16.0.0/12',
                    '192.168.0.0/16',
                );

                foreach ($private_nets as $v) {

                    // Private IP found
                    if ($private_src_ip) {
                        continue;
                    }

                    if ($this->net_match($v, $data_ip)) {
                        $private_src_ip = true;
                    }
                }
                if ($private_src_ip) {
                    // Taking first IP from the list HTTP_X_FORWARDED_FOR
                    $data_ip = $forwarded_ip[0];
                }
            }

            return $data_ip;*/
    return cleantalk_get_real_ip();
  }

  /**
   * From http://php.net/manual/en/function.ip2long.php#82397
   */
  public function net_match($CIDR, $IP) {
    list($net, $mask) = explode('/', $CIDR);
    return (ip2long($IP) & ~((1 << 32 - $mask) - 1)) == ip2long($net);
  }

  /**
   * Function to check response time
   * param string
   * @return int
   */
  function httpPing($host) {

    // Skip localhost ping cause it raise error at fsockopen.
    // And return minimun value
    if ($host == 'localhost') {
      return 0.001;
    }
    $starttime = microtime(true);
    $file = @fsockopen($host, 80, $errno, $errstr, $this->server_timeout);
    $stoptime = microtime(true);
    $status = 0;
    if (!$file) {
      $status = -1;

      // Site is down
    }
    else {
      fclose($file);
      $status = $stoptime - $starttime;
      $status = round($status, 4);
    }
    return $status;
  }

  /**
   * Function convert string to UTF8 and removes non UTF8 characters
   * param string
   * param string
   * @return string
   */
  function stringToUTF8($str, $data_codepage = null) {
    if (!preg_match('//u', $str) && function_exists('mb_detect_encoding') && function_exists('mb_convert_encoding')) {
      if ($data_codepage !== null) {
        return mb_convert_encoding($str, 'UTF-8', $data_codepage);
      }
      $encoding = mb_detect_encoding($str);
      if ($encoding) {
        return mb_convert_encoding($str, 'UTF-8', $encoding);
      }
    }
    return $str;
  }

  /**
   * Function convert string from UTF8
   * param string
   * param string
   * @return string
   */
  function stringFromUTF8($str, $data_codepage = null) {
    if (preg_match('//u', $str) && function_exists('mb_convert_encoding') && $data_codepage !== null) {
      return mb_convert_encoding($str, $data_codepage, 'UTF-8');
    }
    return $str;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Cleantalk::$api_version public property API version to use
Cleantalk::$compressRate private property Data compression rate
Cleantalk::$dataMaxSise private property Maximum data size in bytes
Cleantalk::$data_codepage public property Codepage of the data
Cleantalk::$debug public property Debug level
Cleantalk::$min_server_timeout public property Minimal server response in miliseconds to catch the server
Cleantalk::$server_change public property Flag is change server url
Cleantalk::$server_changed public property Time wotk_url changer
Cleantalk::$server_timeout private property Server connection timeout in seconds
Cleantalk::$server_ttl public property WOrk url ttl
Cleantalk::$server_url public property Cleantalk server url
Cleantalk::$ssl_on public property Use https connection to servers
Cleantalk::$stay_on_server public property Use TRUE when need stay on server. Example: send feedback
Cleantalk::$work_url public property Last work url
Cleantalk::addCleantalkComment public function Function adds to the post comment Cleantalk.ru
Cleantalk::compressData private function Compress data and encode to base64
Cleantalk::createMsg private function Create msg for cleantalk server
Cleantalk::ct_session_ip public function Get user IP behind proxy server
Cleantalk::delCleantalkComment public function Function deletes the comment Cleantalk.ru
Cleantalk::filterRequest private function Filter request params
Cleantalk::getCleantalkCommentHash public function Function to get the message hash from Cleantalk.ru comment
Cleantalk::get_servers_ip public function Function DNS request
Cleantalk::httpPing function Function to check response time param string
Cleantalk::httpRequest private function httpRequest
Cleantalk::isAllowMessage public function Function checks whether it is possible to publish the message
Cleantalk::isAllowUser public function Function checks whether it is possible to publish the message
Cleantalk::net_match public function From http://php.net/manual/en/function.ip2long.php#82397
Cleantalk::sendFeedback public function Function sends the results of manual moderation
Cleantalk::sendRequest private function Send JSON request to servers
Cleantalk::stringFromUTF8 function Function convert string from UTF8 param string param string
Cleantalk::stringToUTF8 function Function convert string to UTF8 and removes non UTF8 characters param string param string