508 lines
15 KiB
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();
|
|
}
|
|
} |