<?php
/**
 * Mysql class
 * 
 * MySQL database abstraction layer
 * 
 * @package linea21\core\system
 * @author $Author: simon $ - linea21 <info@linea21.com>
 * @version $Id: class.mysql.php 4475 2024-08-30 11:54:55Z simon $ 
 * @access public
 * @license http://opensource.org/licenses/gpl-3.0.html
 * MySQL data manipulation
 */

class mysql {
  /*
   * @parameters
   */
  var $DB_HOST = DB_HOST;
  var $DB_USER = DB_USER;
  var $DB_PASS = DB_PASS;
  var $DB_NAME = DB_NAME;
  var $DB_PORT = 3306;
  var $DB_LINK = "";
  var $DB_ADMINMAIL = DB_ADMINMAIL;
  var $RESULT;
  var $DEBUG;
  protected $dispatcher = null;
  
  public function __construct()
  {
  	$this->dispatcher = $GLOBALS['dispatcher'];
  }


  /**
   * mysql::DBInitialise()
   * Initialisation de la connexion
   *
   * @access public
   * @param string $user : utilisateur base de données
   * @param string $pass : password utilisateur base de données
   * @param string $serveur : serveur de base de données
   * @param string $bdd : nom de la base de données
   * @return boolean
   */

  /** @todo @simo remove ? */
  function DBInitialise($user = '', $pass = '', $serveur = '', $bdd = '', $port = '')
  {
  	// Notify the current method
  	$this->dispatcher->notify(new sfEvent($this, 'dbconnector.init', array('user' => $user, 'password' => $pass, 'host' => $serveur, 'db' => $bdd, 'port' => $port)));

    if ($user != '') {
      $this->DB_USER = $user;
    }
    if ($pass != '') {
      $this->DB_PASS = $pass;
    }
    if ($serveur != '') {
      $this->DB_HOST = $serveur;
    }
    if ($bdd != '') {
      $this->DB_NAME = $bdd;
    }
      if ($port != '') {
          $this->DB_PORT = $port;
      }
    return true;
  }

  /**
   * mysql::DBConnexion()
   * connexion Base de données
   *
   * @access public
   * @return boolean
   */

  function DBConnexion()
  {

  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'dbconnector.connect'));

    if(defined('DB_PORT')) $this->DB_PORT = DB_PORT;

    $this->DB_LINK = @mysqli_connect($this->DB_HOST, $this->DB_USER, $this->DB_PASS, $this->DB_NAME, $this->DB_PORT) or die($this->DBError(_t('divers','sql_connect_failed')));
//     $this->DBSelectDB();

    // remove 'ONLY_FULL_GROUP_BY'
    $sub_query = "SELECT REPLACE(@@SESSION.sql_mode, 'ONLY_FULL_GROUP_BY', '')";
    $this->DBQuery("SET SESSION sql_mode=($sub_query);");
    
//     $sql_mode = $this->DBSelect("SELECT @@SESSION.sql_mode");
//     print_r( $sql_mode);

    if(strtolower(CHARSET) == 'utf-8') {
        
        // utf8mb4 not supported before 5.5.3 version
        if((int) mysqli_get_server_version($this->DB_LINK) < (int) 50503) $this->DBQuery("SET NAMES utf8");
        else $this->DBQuery("SET NAMES utf8mb4");
    }
    return true;
  }

  /**
   * mysql::DBSelectDB()
   * Sélection de la Base de données
   *
   * @access public
   * @return boolean
   */

  function DBSelectDB()
  {
  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'dbconnector.selectDB'));
    mysqli_select_db($this->DB_NAME, $this->DB_LINK) or die($this->DBError(_t('divers','db_connect_failed')));
    return true;
  }

  /**
   * mysql::DBError()
   * Gestion des erreurs MySQL
   *
   * @access private
   * @param string $message_err : message retourné par la requête
   * @param string $query : requête provoquant l'erreur
   * @return boolean
   */
  function DBError($message_err, $query = -1)
  {
  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'dbconnector.error'));

    if(is_bool($this->DB_LINK )) $erreur = $message_err . "<br />[<em> error n° " . mysqli_connect_errno(). " : " . mysqli_connect_error() . "</em> ]<br />\n\n";
    else $erreur = $message_err . "<br />[<em> error n° " . mysqli_errno( $this->DB_LINK ) . " : " . mysqli_error( $this->DB_LINK ) . "</em> ]<br />\n\n";
    
    if ($query != -1) {
      $this->_logDbError($query);
      $erreur .= "SQL query : $query<br />\n";
    }
    $date = date("[D d/M/y H:i:s]<br />\n");
    $erreur .= $date . PHP_EOL;
    $erreur .= "running script :" . $_SERVER["SCRIPT_NAME"] . getHttpParameters(). "<br />" . PHP_EOL;;
    $erreur .= "website : " .SITE_ROOT_URL . PHP_EOL;
    if(defined('MOD_DEBUG') && MOD_DEBUG == true) {
      echo $erreur;
    }
    if ($this->DB_ADMINMAIL != -1) @error_log ($erreur, 1, $this->DB_ADMINMAIL);
  }

  /**
   * mysql::DBInsert()
   * Insertion de données dans la BDD
   *
   * @access public
   * @param string $query : requête SQL
   * @param string $returnid : Si $returnid==1 ==> renvoie last_id()
   * @return integer || boolean : $result last_id()
   */

  function DBInsert ($query, $returnid = -1)
  {
  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'dbconnector.insert', array('query' => $query, 'lastid' => $returnid)));

    if (!($this->RESULT = $this->DBQuery($query))) return false;
    // Si returnid=1 on renvoie l'id de l'enregistrement
    // A utiliser uniquement si attribut auto_increment
    if ($returnid == 1) {
      $res = mysqli_insert_id($this->DB_LINK);
    } else {
      $res = true;
    }
    return $res;
  }

  /**
   * mysql::DBQuery()
   * effectue une requête en tous genres -UPDATE - DELETE - SELECT
   *
   * @access public
   * @param string $query : requête SQL
   * @param boolean $ignore_errors
   * @return boolean : $result
   */
  function DBQuery ($query, $ignore_errors = false)
  {
  	global $debugbar;
  	
  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'dbconnector.query', array('query' => $query)));

    if(defined('MOD_DEBUG') && MOD_DEBUG == true && isset($debugbar)) {
    	
    	$this->_logDbQuery($query);
      $debugbar["messages"]->addMessage($query, 'SQL');
      
    }
    if($ignore_errors) {
    	$this->RESULT = mysqli_query($this->DB_LINK, $query);
    } else {
    	$this->RESULT = mysqli_query($this->DB_LINK, $query) or die($this->DbError(_t('divers','sql_query_failed'), $query));
    }

    return $this->RESULT;
  }

  /**
   * mysql::DBSelect()
   * Requêtes - SELECT
   *
   * @access public
   * @param string $query : requête SQL
   * @param string $fetch : renvoie des données, valeur ASSOC (default), ARRAY, OBJECT
   * @param boolean $ignore_errors
   * @return array : $result
   */

  function DBSelect ($query, $fetch = 'ASSOC', $ignore_errors = false)
  {

  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'dbconnector.select', array('query' => $query, 'type' => $fetch)));

    if (!($this->RESULT = $this->DBQuery($query, $ignore_errors))) {
      @mysqli_free_result($this->RESULT);
      return false;
    }
    if ($fetch == 'ARRAY') {
      $i = 0;
      while ($data = @mysqli_fetch_array($this->RESULT)) {
        $table[$i] = $data;
        $i++;
      }
    }
    if ($fetch == 'OBJECT') {
      $i = 0;
      while ($data = @mysqli_fetch_object($this->RESULT)) {
        $table[$i] = $data;
        $i++;
      }
    }
    if ($fetch == 'ASSOC') {
      $i = 0;
      while ($data = @mysqli_fetch_assoc($this->RESULT)) {
        $table[$i] = $data;
        $i++;
      }
    }

    if (!isset($table)) $table = 0;
    return $table;
  }

  /**
   * mysql::DBescape()
   * Echappement  des variables
   *
   * @access public
   * @param string/array $input
   * @return string/array : $output
   */

  function DBescape ($input)
  {

  	// Filter data event + return value
  	$r = $this->dispatcher->filter(new sfEvent($this, 'dbconnector.escape', array('data' => $input)), $input);
  	$input = $r->getReturnValue();

    if(is_array($input)) {

      $output = array();

      foreach ($input as $key => $value) {
      	if(is_string($value)) {
      	    if (version_compare(phpversion(), '7.4.0', '<'))  {
                if (get_magic_quotes_gpc()) $value=stripslashes($value);
      	    }
          // get_magic_quotes_gpc() renvoie FALSE mais des quotes sont quand même ajoutées !
          $value=stripslashes($value); // @simo - since Linea v2.2+ convertBase64Images returns HTML with slashes, we strip them !
          $output[$key] = mysqli_real_escape_string($this->DB_LINK, $value);
        } else {
          $output[$key] =  $value;
        }
      }
    } else {

      // it is a simple string
      if(is_string($input)) {
          if (version_compare(phpversion(), '7.4.0', '<'))  {
            if (get_magic_quotes_gpc()) $input=stripslashes($input);
          }
        $value=stripslashes($input); // @simo - since Linea v2.2+ convertBase64Images returns HTML with slashes, we strip them !
        $output = mysqli_real_escape_string($this->DB_LINK, $input);
      } else {
        $output =  $input;
      }
    }
    return $output;

  }

  /**
   * mysql::DBaffectedRow()
   * Retourne le nombre d'enregistrements affecté par la dernière requête
   *
   * @access public
   * @return integer : $res
   */
  function DBaffectedRow()
  {
  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'dbconnector.affected_rows'));

    $res = mysqli_affected_rows($this->DB_LINK);
    return $res;
  }

  /**
   * _logDbQuery()
   * @access private
   * @param string $q
   * @return void
   */
  function _logDbQuery($q)
  {
  	// Filter data event + return value
  	$r = $this->dispatcher->filter(new sfEvent($this, 'dbconnector.log_query', array('query' => $q)), $q);
  	$q = $r->getReturnValue();

    if(defined('SQL_LOG_DEBUG') && SQL_LOG_DEBUG == 1) {

      $q = str_replace(array("\r", "\n", "\t"),"",$q);
      logfile(LOG_SQL_QUERIES, array($q, get_class($this)));

    }
  }

  /**
   * _logDbError()
   * @access private
   * @param string $q
   * @return void
   */
  function _logDbError($q)
  {
  	// Filter data event + return value
  	$r = $this->dispatcher->filter(new sfEvent($this, 'dbconnector.log_error', array('query' => $q)), $q);
  	$q = $r->getReturnValue();

    $q = str_replace(array("\r", "\n", "\t"),"",$q);
    logfile(LOG_SQL_ERRORS, array($q, $_SERVER["SCRIPT_NAME"], get_class($this)));
  }
  /**
   * mysql::DBclose()
   * Retourne le nombre d'enregistrements affecté par la dernière requête
   *
   * @access public
   * @param string $query : requête SQL
   * @return boolean : $result
   */
  function DBClose()
  {
  	// Notify the end of the current method
  	$this->dispatcher->notify(new sfEvent($this, 'dbconnector.close'));

    @mysqli_close($this->DB_LINK);
  }
  
  /**
   * mysql::DB_getVersion()
   * Retourne le numéro de version sous forme d'entier
   *
   * @access public
   * @return int
   */
  function DB_get_version() 
  {
      return mysqli_get_server_version ($this->DB_LINK);
  }
}

?>