<?

class c_db
{  public $class_name = 'db' ;
   public $DB_LINK ;
   public $host = '' ;
   public $db_name = '' ;
   public $username = '' ;
   public $password = '' ;
   public $charset = 'utf8' ;
   public $debug = '' ;
   public $debug_back_group = 'F9F9F7' ;

 function __construct($connect_code)
   {  $this->class_name=$connect_code ;
      // переносим параметры в объекты
      if (isset($GLOBALS['_SETTING'][$this->class_name]))
      { $this->host=$GLOBALS['_SETTING'][$this->class_name]['host'] ;
        $this->db_name=$GLOBALS['_SETTING'][$this->class_name]['db_name'] ;
        $this->username=$GLOBALS['_SETTING'][$this->class_name]['username'] ;
        $this->password=$GLOBALS['_SETTING'][$this->class_name]['password'] ;
        $this->debug=$GLOBALS['_SETTING'][$this->class_name]['debug'] ;
        $this->connect();
      }
      else
      {
        die('Не определены параметры подключения к серверу БД "'.$this->class_name.'"') ;
      }
      if ($GLOBALS['debug_db']) $this->debug=$GLOBALS['debug_db'] ;
   }

   function __construct_old($options=array())
   {  // переносим параметры в объекты
      $use_setting=($options['setting'])? $options['setting']:$this->class_name ;
      $this->class_name=$use_setting ;
      $this->host=($options['host'])? $options['host']:SETTING($use_setting)['host'] ;
      $this->db_name=($options['db_name'])? $options['db_name']:SETTING($use_setting)['db_name'] ;
      $this->username=($options['username'])? $options['username']:SETTING($use_setting)['username'] ;
      $this->password=($options['password'])? $options['password']:SETTING($use_setting)['password'] ;
        //echo  'db_name='.$this->db_name.'<br>' ;
        // создаем соединение
        $this->connect();
        //  damp_array($this,1,-1) ;
      //else
      //{
      //  die('Не определены параметры подключения к серверу БД "'.$this->class_name.'"') ;
      //}

   }

   function connect() {}

    function print_SQL_debug_begin($sql)
    {  global $debug_db,$__debug_sql_cnt ;
       ?><div style="border:1px solid black;margin:5px;padding:5px;BACKGROUND-COLOR: #<?echo $this->debug_back_group?>;color:black;"><?
       if ($debug_db==2) print_info_sender_function() ;
       ?><span class='red bold'><?echo $__debug_sql_cnt+1 ;?>. </span><?
   	echo $sql.'&nbsp;<i class="fa fa-line-chart v2" cmd="db/explain_sql" sql="'.base64_encode($sql).'" aria-hidden="true"></i><br>' ;
    }
}

// для работы с кластером необходимо в patch задать следующие константы
//  define("_USE_DB_CLUSTER_debug",0); //   // 0/1 - вывод отсладочной информации
//
// работа с классом:
//
// 1. Подключение к кластеру, текущему серверу. Если текущий сервер будет недоступен, будет использован следующий доступный сервер по списку. Возврашает линк на активной коннект к БД
// $db_claster=new i_db_claster($db_host_list, $db_user, $db_password, $db_name) ;
// if ($db_claster->get_active_connect()) $GLOBALS['DB_LINK'] = $db_claster->db_link ;
// else                                   $connect_message    = $db_claster->connect_message ;
//

class i_db_claster
 {
  var $current_host ;
  var $db_hosts ;  // массив всех хостов кластера
  var $db_host ;  // текущий хост
  var $db_name ;
  var $db_username ;
  var $db_password ;
  var $connect_message ;
  var $db_link = null;
  var $next_check = null;
  var $node_config;
  var $cluster_log;

  function __construct($hosts, $user, $password, $dbname)
  {
      // Failsafe for misconfigured server
      $this->db_host=(is_array($hosts))? $hosts:[$hosts] ;

      $this->db_name = $dbname;
      $this->db_username = $user;
      $this->db_password = $password;

      $this->cluster_log=$_SERVER['DOCUMENT_ROOT'].'/ini/cluster.log';

      if (_CLUSTER_NODE_ID)
      {   $this->node_config = $_SERVER['DOCUMENT_ROOT'].'/ini/node_'._CLUSTER_NODE_ID;
          $text=file_get_contents($this->node_config) ;
          if ($text === false) { $this->current_host = _CLUSTER_NODE_ID;
                                 $this->next_check = null;
                                 $this->save_node($this->current_host, $this->next_check);
                               }
          else
          { $data = json_decode($text);
            $this->current_host = $data->current_host;
            $this->next_check = $data->next_check;
          }

          if (time() > $this->next_check) { $this->current_host = _CLUSTER_NODE_ID; }

      // Failsafe for misconfigured system
         if ($this->current_host > count($this->db_host) - 1) { $this->current_host = 0; }
     }
  }

  function connect($host)
  {     if (!$host) $host=0 ;
        if (_USE_DB_CLUSTER_debug) echo 'Проверяем коннект # '.$host ;
        ob_start();
        $this->db_link = @mysqli_connect(
            $host,
            $this->db_username,
            $this->db_password,
            $this->db_name
        );
        $this->connect_message = ob_get_clean();
        $result=is_object($this->db_link) ;
        if (!$result) $this->reg_log('connect_node',$host,$this->db_host[$host],0) ;
        if ($_GET['check_connect_db']) $this->reg_log('check_connect_db',$host,$this->db_host[$host],($result)? 1:0) ;
        return $result;
  }

  function get_active_connect()
  {
    $retries = count($this->db_host);
    $host = $this->current_host;

    while (!$this->connect($this->db_host[$host]) && $retries > 0)
    {
        $retries--;
        $host++;
        if ($host > count($this->db_host) - 1) $host = 0;
    }

    if ($host != $this->current_host)
    {
        $this->save_node($host, time() + (1 * 60 * 60)); // schedule next check in one hour
    }

    $GLOBALS['current_DB_HOST']=$this->db_host[$host] ;

    return is_object($this->db_link);
  }

  function save_node($host, $next_check)
  {
    $text=json_encode([
        'current_host' => $host,
        'next_check' => $next_check
    ]);
    file_put_contents($this->node_config, $text, LOCK_EX);

    $this->reg_log('select_node',$host,$this->db_host[$host],1) ;

    if (_USE_DB_CLUSTER_debug) echo 'Конфигурация подключения к кластеру была изменена<br>' ;
  }

  function reg_log($text,$host_id,$host_ip,$host_status)
  {
      $_arr_line=[] ;
      $_arr_line[]=date('d.m.Y H:i:s') ;
      $_arr_line[]=$_SERVER['SERVER_ADDR'] ;
      $_arr_line[]=$text ;
      $_arr_line[]=$host_id ;
      $_arr_line[]=$host_ip ;
      $_arr_line[]=$host_status ;
      $line=implode(',',$_arr_line)."\n" ;
      ob_start() ;
      file_put_contents($this->cluster_log, $line, FILE_APPEND);
      ob_get_clean() ;
  }
 }

?>
