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 "
{$fname}".PHP_EOL.$sql.PHP_EOL.print_r($params?:Array(),1).PHP_EOL.PHP_EOL.print_r(sqlsrv_errors(), true)."
"; }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(); } }