HANYANG_REACT/lib/db/mssql.class.php

508 lines
15 KiB
PHP

<?php
class DB_Mssql {
public $dbconn;
public $dboption;
public $query_print = false;
public $query_record = true;
public function __construct($db_option=""){
global $__dbconn__;
$_config_db_option = @parse_ini_file("db_config.php");
$this->dboption = $db_option ?: $_config_db_option;
if( !$db_option && $__dbconn__ ) { //기본 Connection을 이용
$this->dbconn = $__dbconn__;
}else{ //전용 Connection을 이용
$this->dbConn($db_option);
}
}
public function dbConn($db_option=""){
$_config_db_option = @parse_ini_file("db_config.php");
if( !$_config_db_option ){
$_config_db_option = @parse_ini_file(_ROOT_PATH_."/config/db_config.php");
}
if( !$db_option ) $db_option = array();
/*위에 있어서 필요없는 코드*/
$db_option["database_type"] = $db_option["database_type"] ?: $_config_db_option["database_type"];
$db_option["database_host"] = $db_option["database_host"] ?: $_config_db_option["database_host"];
$db_option["database_port"] = $db_option["database_port"] ?: $_config_db_option["database_port"];
$db_option["database_name"] = $db_option["database_name"] ?: $_config_db_option["database_name"];
$db_option["database_user"] = $db_option["database_user"] ?: $_config_db_option["database_user"];
$db_option["database_pass"] = $db_option["database_pass"] ?: $_config_db_option["database_pass"];
$db_option["database_encode"] = $db_option["database_encode"] ?: $_config_db_option["database_encode"];
$db_option["database_charset"] = $db_option["database_charset"] ?: $_config_db_option["database_charset"];
$db_option["database_old"] = $db_option["database_old"] ?: $_config_db_option["database_old"];
if( !$this->dboption ){
$this->dboption = $db_option;
}
$addr = "{$db_option['database_host']},{$db_option['database_port']}";
$option = Array(
"Database" => $db_option['database_name'],
"Uid" => $db_option['database_user'],
"PWD" => $db_option['database_pass'],
"CharacterSet" => $db_option['database_encode'],
"TrustServerCertificate" => "yes",
"ConnectionPooling" => 0,
);
$conn = sqlsrv_connect( $addr, $option);
if( $conn ){
$this->dbconn = $conn;
if( defined("TB_query_log") ){
$this->tableExists(TB_query_log);
}
return $conn;
}else{
die('Could not connect: ' . print_r(sqlsrv_errors(), true));
}
}
public function qry($sql, $sqlrow="", $options="", $print=""){
return $this->cqry($sql, $sqlrow, $options, $print);
}
public function cqry($sql, $sqlrow="", $options="", $print="", $rev=1){
if( $rev === 1 ){
$anrow = $this->anqry($sqlrow);
$params = $anrow['params'];
}else{
$params = $sqlrow;
}
if( $print || $this->query_print ){
echo $this->mkstr($sql,$params?:Array());
}
if( $print ){exit;}
$stmt = @sqlsrv_query($this->dbconn, $sql, $params?:Array(), $options?:Array());
if( $stmt ){
$result = "SUCCESS";
$rst = $stmt;
}else{
$bpage = debug_backtrace();
$fname = $bpage[count($bpage)-1]['file'];
if( !$GLOBALS['NO_SQL_ERR'] ){
$result = print_r(sqlsrv_errors(), true);
echo "<pre>{$fname}".PHP_EOL.$sql.PHP_EOL.print_r($params?:Array(),1).PHP_EOL.PHP_EOL.print_r(sqlsrv_errors(), true)."</pre>";
}else{
$result = "NO_SQL_ERROR";
}
$rst = false;
}
if( $this->query_record ){
$this->putQueryLog( $sql, $params, $result );
}
return $rst;
}
public function query($sql, $params="", $options="", $print=""){
$stmt = $this->qry($sql, $params?:Array(), $options?:Array(), $print);
if( !$stmt ) return false;
$rows = Array();
while( $row = $this->fetch_array($stmt) ){
$rows[] = $row;
}
return $rows;
}
public function call( $procedure, $params=array() ){
$anrow = $this->anqry($params);
$sql = "{CALL {$procedure} (".implode(",",$anrow['val']).")}";
return $this->qry($sql, $params);
}
public function call_output( $procedure, $params=array() ){
$anrow = $this->anqry($params);
$sql = "{CALL {$procedure} ".implode(",",$anrow['val']).")}";
return $this->cqry($sql, $params,"","",2);
}
public function call_next( $stmt ){
return @sqlsrv_next_result($stmt);
}
public function call_all( $procedure, $params=array() ){
$rst = $this->call( $procedure, $params );
if( $rst ){
$rows = Array();
while( $row = $this->fetch_array($rst) ){
$rows[] = $row;
}
return $rows;
}
return $rst;
}
public function exec( $procedure, $params=array() ){
$anrow = $this->anqry($params);
$sql = "EXEC {$procedure} ".implode(",",$anrow['val'])."";
return $this->qry($sql, $params);
}
public function exec_output( $procedure, $params=array() ){ //$params => 숫자키 배열
$anrow = $this->anqry($params);
$sql = "EXEC {$procedure} ".implode(",",$anrow['val'])."";
return $this->cqry($sql, $params,"","",2);
}
public function exec_output_merge( $procedure, $params=array() ){ //$params => 문자 키 배열. output요소가 array(array("값",SQLSRV_PARAM_OUT)) 가 되어야 한다.
$oparams = Array();
foreach( $params as $val ){
$oparams[] = $val;
}
$anrow = $this->anqry($oparams);
$sql = "EXEC {$procedure} ".implode(",",$anrow['val'])."";
return $this->cqry($sql, $oparams,"","",2);
}
public function exec_next( $stmt ){
return @sqlsrv_next_result($stmt);
}
public function exec_all( $procedure, $params=array() ){
$rst = $this->exec( $procedure, $params );
if( $rst ){
$rows = Array();
while( $row = $this->fetch_array($rst) ){
$rows[] = $row;
}
return $rows;
}
return $rst;
}
public function queryFirstField($sql, $params="", $options="", $print=""){
$stmt = $this->qry($sql, $params?:Array(), $options?:Array(), $print);
if( !$stmt ) return false;
return $this->result($stmt,0,0);
}
public function queryFirstRow($sql, $params="", $options="", $print=""){
$stmt = $this->qry($sql, $params?:Array(), $options?:Array(), $print);
if( !$stmt ) return false;
return $this->fetch_array($stmt);
}
public function pqry($sql, $params="", $options=""){
return $this->qry($sql, $params?:Array(), $options?:Array(), 1);
}
public function pquery($sql, $params="", $options=""){
return $this->query($sql, $params?:Array(), $options?:Array(), 1);
}
public function fetch_row($stmt){
if( $stmt ){
return @sqlsrv_fetch_array($stmt, 1);
}
return "sqlsrv_fetch_array Error #1";
}
public function fetch_array($stmt){
if( $stmt ){
return @sqlsrv_fetch_array($stmt, 2);
}
echo "sqlsrv_fetch_array Error #2";
}
public function fetch_object($stmt){
if( $stmt ){
return @sqlsrv_fetch_object($stmt, 2);
}
echo "sqlsrv_fetch_object Error #2";
}
public function num_rows($stmt){
if( $stmt ){
return @sqlsrv_num_rows($stmt);
}
echo "sqlsrv_num_rows Error";
}
public function select_count($tb, $where="", $whererow="", $print=""){
$where = $where?:"1=1";
$sql = "select count(*) from {$tb} where {$where}";
return $this->queryFirstField($sql, $whererow?:array(), $print);
}
public function insert($tb, $row, $print=""){
$anrow = $this->anqry($row);
$sql = "insert into {$tb} (".implode(",",$anrow['fld']).") values (".implode(",",$anrow['val']).")";
$rst = $this->qry($sql, $anrow['params'], "", $print);
return (bool)$rst;
}
public function update($tb, $row, $where="", $whererow="", $print=""){
$where = $where?:"1=1";
$anrow = $this->anqry($row);
$sql = "update {$tb} set ";
$setrow = array();
foreach( (array)$anrow['fld'] as $k => $v ){
$setrow[] = " {$v} = {$anrow['val'][$k]} ";
}
$sql.= implode(",",$setrow)." where {$where}";
foreach( (array)$whererow as $k => $v ){
$anrow['params'][] = $v;
}
$rst = $this->qry($sql, $anrow['params'], "", $print);
return (bool)$rst;
}
public function insertupdate($tb, $ins_row, $upt_row, $where="", $whererow="", $print=""){
$where = $where?:"1=1";
$ins_anrow = $this->anqry($ins_row);
$upt_anrow = $this->anqry($upt_row);
$setrow = array();
foreach( (array)$upt_anrow['fld'] as $k => $v ){
$setrow[] = " {$v} = {$upt_anrow['val'][$k]} ";
}
$sql = "merge into {$tb} as A using (select 1 as dual) as B on ({$where}) ";
$sql.= "when matched then ";
$sql.= "update set ".implode(",",$setrow)." ";
$sql.= "when not matched then ";
$sql.= "insert (".implode(",",$ins_anrow['fld']).") values (".implode(",",$ins_anrow['val']).");";
$params = array_merge($whererow, $upt_anrow['params'], $ins_anrow['params']);
$rst = $this->qry($sql, $params?:Array(), "", $print);
return (bool)$rst;
}
public function delete($tb, $where, $whererow="", $print=""){
$where = $where?:"1=1";
$sql = "delete from {$tb} where {$where}";
$rst = $this->qry($sql, $whererow?:Array(), "", $print);
return (bool)$rst;
}
public function insertId($tb){
if( $tb ){
$sql = "select ident_current(?)";
return $this->queryFirstField($sql,array($tb));
}else{
$sql = "select @@identity";
return $this->queryFirstField($sql);
}
//@@IDENTITY 현재 세션의 테이블에서 생성된 마지막 ID 값을 반환합니다. --// 현재 세션내 모든 테이블에서 발생하는 ID값중 마지막
//SCOPE_IDENTITY() 현재 세션의 테이블에서 생성된 마지막 ID 값을 반환합니다. --// 현재 세션내 특
//IDENT_CURRENT() 임의 세션 및 범위에 있는 특정 테이블에 생성된 값을 반환합니다.
}
public function anqry($row){ // 필드와 값 분리 + assign value
$fld = array();
$val = array();
$params = array();
foreach( (array)$row as $k => $v ){
$fld[] = $k;
if( $this->chkeval($v) ){
$val[] = $this->valeval($v);
}else{
$val[] = "?";
$params[] = $v;
}
}
return Array( "fld"=>$fld, "val"=>$val, "params"=>$params );
}
public function result($stmt, $rows=0, $cols=0){
$rows = intval($rows);
for( $a=0 ; $a<=$rows ; $a++ ){
if( is_int($cols) ){
$arr = $this->fetch_row($stmt);
}else{
$arr = $this->fetch_array($stmt);
}
}
return is_array($arr)?$arr[$cols]:$arr;
}
public function mkstr( $sql, $params="" ){ //쿼리 출력
$params = $params?:Array();
$str = $sql;
for( $a=0 ; $a < substr_count($sql, "?") ; $a++ ){
$str = $this->str_freplace("?","'{$params[$a]}'",$str);
}
return $str;
}
public function str_freplace( $needle, $replace, $str ){
$pos = strpos($str, $needle);
if( $pos !== false ){
$nstr = substr_replace($str, $replace, $pos, strlen($needle));
}
return $nstr;
}
public function limit($start, $length){
if( $length > 0 ){
return " offset {$start} rows fetch next {$length} rows only ";
}
return '';
}
public function addLimit($sql, $ordby, $start, $length){
$ordby = $ordby?:1;
$start = $start?:0;
$length = $length?:999999999998;
if( $this->dboption["database_version"] && $this->dboption["database_version"] <= "2008" ){
$start = $start+1;
$length = $start+$length-1;
$sql = "select * from ( select *, row_number() over(order by {$ordby}) as ROWNUM from ({$sql}) as tblsub ) as tblmain where ROWNUM between {$start} and {$length}";
}else {
$sql = "{$sql} order by {$ordby} offset {$start} rows fetch next {$length} rows only ";
}
return $sql;
}
public function sqleval($str){
return chr(27).$str;
}
public function chkeval($str){
if( !is_array($str) && preg_match("/^".chr(27)."/ims",$str) ){
return true;
}
return false;
}
public function valeval($str,$val=""){
return preg_replace("/^".chr(27)."/ims",$val,$str);
}
public function tableExists( $table ){
if( !$table ) return false;
$tbl = explode(".",$table);
if( !$tbl[1] ){
$database = "dbo";
$table = $tbl[0];
}else{
$database = $tbl[0];
$table = $tbl[1];
}
$cnt = $this->queryFirstField("select 1 from Information_schema.tables where TABLE_TYPE = ? and TABLE_NAME = ?", array(
"BASE TABLE",
$table
));
if( $cnt ){
return true;
}else{
if( !( $fs = fopen( TB_schema_file, "r") ) ) return false;
while( $rw = fgets($fs, 255) ){
$tbname = defined("TB_HEAD")?preg_replace("/^".TB_HEAD."/","",$table):$table;
if( chop($rw) == "[{$tbname}]" ) break;
}
$query = "create table {$database}.{$table} ";
while( $rw = fgets($fs, 255) ){
if( chop($rw) != "-end-" ){
$rw = preg_replace("/ comment[ \=].*\'.*\'/ims","",$rw);
$rw = preg_replace("/CONSTRAINT pk\_/ims","CONSTRAINT pk_".TB_HEAD,$rw);
$rw = preg_replace("/CONSTRAINT fk\_/ims","CONSTRAINT fk_".TB_HEAD,$rw);
$rw = preg_replace("/CONSTRAINT uk\_/ims","CONSTRAINT uk_".TB_HEAD,$rw);
$rw = preg_replace("/CONSTRAINT ik\_/ims","CONSTRAINT ik_".TB_HEAD,$rw);
$query .= $rw;
}else{
break;
}
}
fclose($fs);
$rst = $this->qry($query);
if( $rst ){
include TB_data_file;
if( isset($table_base_data[$tbname]) ){
foreach( $table_base_data[$tbname] as $val ){
$this->insert($table, $val);
}
}
}
return $rst;
}
}
public function putQueryLog( $save_sql, $save_params, $result ){
global $__dbconn__;
if( !defined("TB_query_log") ) return false;
if( preg_match("/Information_schema.tables/ims", $save_sql) ) return false;
$this->delQueryLog(1);
$qryrow = Array(
"query_date" => $this->sqleval("CURRENT_TIMESTAMP"),
"query_result" => $result,
"host_name" => $this->dboption["database_host"],
"db_name" => $this->dboption["database_name"],
"query_string" => $save_sql,
"query_params" => @print_r($save_params, true),
"visit_sess" => $_SESSION['visit_sess'],
"member_id" => $GLOBALS['_Umem']['member_id'],
);
$anrow = $this->anqry($qryrow);
$sql = "insert into ".TB_query_log." (".implode(",",$anrow['fld']).") values (".implode(",",$anrow['val']).")";
return @sqlsrv_query($__dbconn__, $sql, $anrow['params']);
}
public function delQueryLog( $month = 6 ){
global $__dbconn__;
if( rand(1,100) === 50 ){ // 1% 확률로 삭제
$month= -1*abs($month);
$sql = "delete from ".TB_query_log." where query_date < dateadd(month, {$month}, getdate()) ";
return @sqlsrv_query($__dbconn__, $sql);
}
return false;
}
public function callTransaction(){
return sqlsrv_begin_transaction( $this->dbconn );
}
public function callCommit(){
return sqlsrv_commit( $this->dbconn );
}
public function callRollBack(){
return sqlsrv_rollback( $this->dbconn );
}
public function setPrint(){
$this->query_print = true;
}
public function resetPrint(){
$this->query_print = false;
}
public function setRecord(){
$this->query_record = true;
}
public function resetRecord(){
$this->query_record = false;
}
}
class BaseDB {
public $DB;
public $lcrypt;
public function __construct($db_option=""){
$this->DB = new DB_Mssql($db_option);
$this->lcrypt = new lcrypt();
}
}