<?php
/**------------------------------------------------
*
* Rooty, 2018 <rooty@rooty.me>
*
*
* This software is protected by copyright, please
* read the file COPYRIGHT.
* This program is distributed in the hope that it
* will be useful, but without any warranty; without
* even the implied warranty of merchantability or
* fitness for a particular purpose. Please
* read the file LICENCE.
*
*                               msaccess.php
*                            -------------------
*   begin                : Saturday, Feb 13, 2001
*   copyright            : (C) 2001 The phpBB Group
*   email                : support@phpbb.com
*
*   $Id: odbc.php,v 1.3 2006/10/10 21:38:55 tristan Exp $
*
*
*   This program is free software; you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation; either version 2 of the License, or
*   (at your option) any later version.
*
*
*Fichier odbc.php
*
*Ce fichier contient la classe d'accès aux données pour ODBC
*
* @copyright Copyright &copy; 2009-2018, Rooty
* @since 2018/09/28
* @version 1.8.2.2
* @link http://www.phpbb.com
* @package system_data_source
* @subpackage database
* @modify by Initiance <www.initiance.com|olivier@initiance.com>
* @docreview Tristan <tristan@initiance.com> | 30-10-2005
*
*/

#####################################################################################################
################################# Parametrage
#####################################################################################################
/**
* declaration du system... si cette variable n'est pas définie, les fichier inclus ne marche pas...
* cette variable est déclarée sur la page d'execution du script.
*<p> if ( !defined('SYSTEM_IN') )
* {
* die("Hacking attempt");
* }</p>
*/
if ( !defined('SYSTEM_IN') )
{
 die("Hacking attempt");
}

/**
* classe ODBC
*
* classe de gestion de Odbc
*
* @package system_data_source
* @subpackage database
*/
class ODBC extends Database
{

/**#@+
* @access public
*/

/**
* @var entier
* @desc identifiant de la connection a la base
*/
	var $db_connect_id;
/**
* @var tableau
* @desc tableau contenant les identifiants de resultat
*/
	var $result_ids = array();
/**
* @var query_result
* @desc pointeur de résultat sur requete SELECT
*/
	var $result;
/**
* @var entier
* @desc Identifiant en cours (Requete INSERT)
*/
	var $next_id;
/**
* @var tableau
* @desc tableau contenant le nombre de resultats par requetes
*/
	var $num_rows = array();
/**
* @var tableau
* @desc Contient une ligne de résultat
*/
	var $current_row = array();
/**
* @var tableau
* @desc Contient le nom des champs d'une requete
*/
	var $field_names = array();
/**
* @var tableau
* @desc Contient le type des champs d'une requete
*/
	var $field_types = array();
/**
* @var tableau
* @desc Contient tout le jeu de résultats
*/
	var $result_rowset = array();
/**
* @var entier
* @desc Nombre total de requetes effectuées
*/
var $num_queries = 0;
var $in_transaction;

/**#@-*/
	//
	// Constructor
	//

/**
*Constructeur de la classe ODBC
*
*<p>Initialise la connection a la source de données ODBC</p>
*
* @param chaine Nom de l'hote
* @param chaine Nom d'utilisateur
* @param chaine Mot de passe de connection
* @param chaine Nom de la base a utiliser
* @param booléen Connection persistante
*/
	function ODBC($sqlserver, $sqluser, $sqlpassword, $database, $persistency = true)
	{
		$this->__construct($sqlserver, $sqluser, $sqlpassword, $database, $persistency);
	}

	function __construct($sqlserver, $sqluser, $sqlpassword, $database, $persistency = true)
	{
		$this->persistency = $persistency;
		$this->server = $sqlserver;
		$this->user = $sqluser;
		$this->password = $sqlpassword;
		$this->dbname = $database;

		$this->db_connect_id = ($this->persistency) ? odbc_pconnect($this->server, $this->user, $this->password) : odbc_connect($this->server, $this->user, $this->password);

		if ( $this->db_connect_id )
		{
			return $this->db_connect_id;
		}else{
			/* Olivier 12/07/04 */
			$seuil=1;
			$classe="ODBC";
			$message="Erreur de configuration de la base de donnée:Base non disponible";
			addError($seuil,$classe,$message, __line__, __file__);
			return false;
		}
	}
	//
	// Other base methods
	//

/**
*fermeture de connection
*
* fonction qui ferme la connection a la source de données
*
* @return booléen
*/
	function sql_close()
	{
		if($this->db_connect_id)
		{
			if( $this->in_transaction )
			{
				@odbc_commit($this->db_connect_id);
			}

			if( count($this->result_rowset) )
			{
				unset($this->result_rowset);
				unset($this->field_names);
				unset($this->field_types);
				unset($this->num_rows);
				unset($this->current_row);
			}

			return @odbc_close($this->db_connect_id);
		}
		else
		{
			return false;
		}
	}

	//
	// Query method
	//
	
/**
*fonction de requete SQL
*
* permet de faire une requete sur la connection ODBC ouverte 
*
* @param chaine Requete SQL
* @param booléen inutilisé dans ce cas
* @return result renvoie un pointeur de resultat ou faux si erreur de requete
*/	
	function sql_query($query = "", $transaction = FALSE)
	{
		$query=Database::rewriteQuery($query);
		if( $query != "" )
		{
			$this->num_queries++;

			if( $transaction == BEGIN_TRANSACTION && !$this->in_transaction )
			{
				if( !odbc_autocommit($this->db_connect_id, false) )
				{
					return false;
				}
				$this->in_transaction = TRUE;
			}

			$query = str_replace("LOWER(", "LCASE(", $query);

			if( preg_match("/^SELECT(.*?)(LIMIT ([0-9]+)[, ]*([0-9]+)*)?$/s", $query, $limits) )
			{
				$query = $limits[1];

				if( !empty($limits[2]) )
				{
					$row_offset = ( $limits[4] ) ? $limits[3] : "";
					$num_rows = ( $limits[4] ) ? $limits[4] : $limits[3];

					$query = "TOP " . ( $row_offset + $num_rows ) . $query;
				}

				$this->result = odbc_exec($this->db_connect_id, "SELECT $query");

				if( $this->result )
				{
					if( empty($this->field_names[$this->result]) )
					{
						for($i = 1; $i < odbc_num_fields($this->result) + 1; $i++)
						{
							$this->field_names[$this->result][] = odbc_field_name($this->result, $i);
							$this->field_types[$this->result][] = odbc_field_type($this->result, $i);
						}
					}

					$this->current_row[$this->result] = 0;
					$this->result_rowset[$this->result] = array();

					$row_outer = ( isset($row_offset) ) ? $row_offset + 1 : 1;
					$row_outer_max = ( isset($num_rows) ) ? $row_offset + $num_rows + 1 : 1E9;
					$row_inner = 0;

					while( odbc_fetch_row($this->result, $row_outer) && $row_outer < $row_outer_max )
					{
						for($j = 0; $j < count($this->field_names[$this->result]); $j++)
						{
							$this->result_rowset[$this->result][$row_inner][$this->field_names[$this->result][$j]] = stripslashes(odbc_result($this->result, $j + 1));
						}

						$row_outer++;
						$row_inner++;
					}

					$this->num_rows[$this->result] = count($this->result_rowset[$this->result]);

					odbc_free_result($this->result);
				}

			}
			else if( eregi("^INSERT ", $query) )
			{
				$this->result = odbc_exec($this->db_connect_id, $query);

				if( $this->result )
				{
					$result_id = odbc_exec($this->db_connect_id, "SELECT @@IDENTITY");
					if( $result_id )
					{
						if( odbc_fetch_row($result_id) )
						{
							$this->next_id[$this->db_connect_id] = odbc_result($result_id, 1);
							$this->affected_rows[$this->db_connect_id] = odbc_num_rows($this->result);
						}
					}
				}
			}
			else
			{
				$this->result = odbc_exec($this->db_connect_id, $query);

				if( $this->result )
				{
					$this->affected_rows[$this->db_connect_id] = odbc_num_rows($this->result);
				}
			}

			if( !$this->result )
			{
				if( $this->in_transaction )
				{
					odbc_rollback($this->db_connect_id);
					odbc_autocommit($this->db_connect_id, true);
					$this->in_transaction = FALSE;
				}

				return false;
			}

			if( $transaction == END_TRANSACTION && $this->in_transaction )
			{
				$this->in_transaction = FALSE;

				if ( !@odbc_commit($this->db_connect_id) )
				{
					odbc_rollback($this->db_connect_id);
					odbc_autocommit($this->db_connect_id, true);
					return false;
				}
				odbc_autocommit($this->db_connect_id, true);
			}

			return $this->result;
		}
		else
		{
			if( $transaction == END_TRANSACTION && $this->in_transaction )
			{
				$this->in_transaction = FALSE;

				if ( !@odbc_commit($this->db_connect_id) )
				{
					odbc_rollback($this->db_connect_id);
					odbc_autocommit($this->db_connect_id, true);
					return false;
				}
				odbc_autocommit($this->db_connect_id, true);
			}

			return true;
		}
	}

	//
	// Other query methods
	//
/**
*Nombre de resultats retournés
*
*permet de récuperer le nombre de lignes retournées lors de la dernière requête effectuée.
*
* @param entier (facultatif) identifiant de requete , utilise la dernière requete par defaut
* @return entier nombre de résultats
*/	
	function sql_numrows($query_id = 0)
	{
		if( !$query_id )
		{
			$query_id = $this->result;
		}

		return ( $query_id ) ? $this->num_rows[$query_id] : false;
	}
	

/**
*Nombre de champs 
*
* retourne le nombre de champs de la derniere requete effectuée 
*
* @param entier (facultatif) identifiant de requete , utilise la dernière requete par defaut
* @return entier nombre de champs
*/
	
	function sql_numfields($query_id = 0)
	{
		if( !$query_id )
		{
			$query_id = $this->result;
		}

		return ( $query_id ) ? count($this->field_names[$query_id]) : false;
	}
	
	
/**
*Nom d'un champ
*
* retourne le nom du champ placé a offset
*
* @param entier emplacement du champ
* @param entier (facultatif) identifiant de requete , utilise la dernière requete par defaut
* @return chaine nom du champ
*/	

	function sql_fieldname($offset, $query_id = 0)
	{
		if( !$query_id )
		{
			$query_id = $this->result;
		}

		return ( $query_id ) ? $this->field_names[$query_id][$offset] : false;
	}

/**
*Type d'un champ
*
* retourne le type du champ placé a offset
*
* @param entier emplacement du champ
* @param entier (facultatif) identifiant de requete , utilise la dernière requete par defaut
* @return chaine type de champ
*/	
	function sql_fieldtype($offset, $query_id = 0)
	{
		if( !$query_id )
		{
			$query_id = $this->result;
		}

		return ( $query_id ) ? $this->field_types[$query_id][$offset] : false;
	}


/**
*Obtenir un résultat
*
* retourne l'enregistrement courant sous forme de tableau 
*
* @param entier facultatif) identifiant de requete , utilise la dernière requete par defaut
* @return tableau tableau contenant les différents champs
*/
	
	function sql_fetchrow($query_id = 0)
	{
		if( !$query_id )
		{
			$query_id = $this->result;
		}

		if( $query_id )
		{
			return ( $this->num_rows[$query_id] && $this->current_row[$query_id] < $this->num_rows[$query_id] ) ? $this->result_rowset[$query_id][$this->current_row[$query_id]++] : false;
		}
		else
		{
			return false;
		}
	}

/**
*Obtenir tous les résultats
*
* retourne tous les enregistrements courants (derniere requete effectuée) sous forme de tableau 
*
* @param entier  (facultatif) identifiant de requete , utilise la dernière requete par defaut
* @return tableau_2D tableau à deux dimensions contant tous les enregistrement
*/
	function sql_fetchrowset($query_id = 0)
	{
		if( !$query_id )
		{
			$query_id = $this->result;
		}
		if( $query_id )
		{
			return ( $this->num_rows[$query_id] ) ? $this->result_rowset[$query_id] : false;
		}
		else
		{
			return false;
		}
	}

/**
*Obtenir un champ particulier d'un resultat
*
* retourne un champ déterminé d'un enregistrement déterminé . 
*
* @param entier (ou chaine) champ a renvoyer
* @param entier (facultatif) identifiant de l'enregistrement (dernier par defaut)
* @param entier (facultatif) identifiant de requete , utilise la dernière requete par defaut
* @return chaine valeur du champ
*/
	
	function sql_fetchfield($field, $row = -1, $query_id = 0)
	{
		if( !$query_id )
		{
			$query_id = $this->result;
		}

		if( $query_id )
		{
			if( $row < $this->num_rows[$query_id] )
			{
				$getrow = ($row == -1) ? $this->current_row[$query_id] - 1 : $row;

				return $this->result_rowset[$query_id][$getrow][$this->field_names[$query_id][$field]];
			}
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}
	}

/**
*Déplacement de pointeur de résultat
*
* permet de déplacer le pointeur de résultat.
*
* @param entier ligne
* @param entier (facultatif) identifiant de requete , utilise la dernière requete par defaut
* @return result nouveau pointeur de resultat
*/
	function sql_rowseek($offset, $query_id = 0)
	{
		if( !$query_id )
		{
			$query_id = $this->result;
		}

		if( $query_id )
		{
			$this->current_row[$query_id] = $offset - 1;
			return true;
		}
		else
		{
			return false;
		}
	}
	
/**
*Identifiant d'insertion
*
* permet d'obtenir l'identifiant d'insertion (Requete INSERT)
*
* @return entier identifiant
*
*/
	function sql_nextid()
	{
		return ( $this->next_id[$this->db_connect_id] ) ? $this->next_id[$this->db_connect_id] : false;
	}


/**
*Nombre d'enregistrements modifiés
*
* retourne le nombre d'enregistrements affectés par la derniere requete.
*
* @return entier nombre d'enregistrements modifiés
*/	
	function sql_affectedrows()
	{
		return ( $this->affected_rows[$this->db_connect_id] ) ? $this->affected_rows[$this->db_connect_id] : false;
	}

/**
*Liberer l'espace mémoire
*
* permet de liberer la memoire occupée par le pointeur de résultat
*
* @param entier (facultatif) identifiant de requete , utilise la dernière requete par defaut
* @return booléen effectué avec succès
*/
	function sql_freeresult($query_id = 0)
	{
		if( !$query_id )
		{
			$query_id = $this->result;
		}
		unset($this->num_rows[$query_id]);
		unset($this->current_row[$query_id]);
		unset($this->result_rowset[$query_id]);
		unset($this->field_names[$query_id]);
		unset($this->field_types[$query_id]);

		return true;
	}

/**
*Fonction d'erreur
*
* retourne un tableau contenant le numero et le message d'erreur
*
* @return tableau contenant les index ['message'] et ['code']
*/
	function sql_error()
	{
		//$error['code'] = "";//odbc_error($this->db_connect_id);
		$error['code'] = odbc_error($this->db_connect_id);
		//$error['message'] = "Error";//odbc_errormsg($this->db_connect_id);
		$error['message'] = odbc_errormsg($this->db_connect_id);
		return $error;
	}
}
?>
