<?php
    
/**
* mysqli 查询数据库;
* @Author Cui;
* @Data 2014/08/05
*/
class
db_mysqli
{
    
# mysqli 类;
    
private
$db
;
        
    
# 表;
    
private
$sqlTables
;
        
    
# where条件;
    
private
$sqlWhere
;
        
    
# 数据库字段;
    
private
$sqlFields
;
        
    
# 排序;
    
private
$sqlOrder
;
        
    
# 分页;
    
private
$sqlLimit
;
        
    
# prepare;
    
private
$sqlPrepare
;
    
    
# 数据;
    
private
$data
;
    
    
# 最后的sql语句;
    
private
$sql
;
        
    
# 预查询对象;
    
private
$stmt
;   
    
    
# 错误信息;
    
private
$error
;
    
    
    
# 构造方法;
    
public
function
__construct(
$connect
) {
    
        
if
( !
extension_loaded
(
'mysqli'
) ) {
            
exit
(
'Mysqli Unload!'
);
        
}
    
        
@
$this
->db =
new
mysqli(
$connect
[
'host'
],
$connect
[
'user'
],
$connect
[
'password'
] );
    
        
if
( mysqli_connect_errno() ) {
            
exit
( mysqli_connect_error() );           
        
}   
            
        
$this
->db->select_db(
$connect
[
'db'
] );
        
$this
->db->set_charset(
$connect
[
'charset'
] );
    
    
}
    
    
# 魔术方法;
    
public
function
__invoke (
$tables
=
''
) {
        
$this
->table(
$tables
);
        
return
$this
;
    
}
    
    
public
function
__call(
$method
=
""
,
$var
=
""
) {
        
exit
(
'你调用了一个未定义的方法'
.
$method
.
'!'
);
    
}
    
    
# 设置表;
    
public
function
table(
$tables
) {
        
if
(
is_string
(
$tables
) ) {
            
$tables
=
array
(
$tables
);
        
}
        
$this
->sqlTables =
$tables
;
        
return
$this
;
    
}
    
    
# 设置字段信息;
    
public
function
field(
$fields
=
''
) {
        
if
(
is_string
(
$fields
) ) {
            
$fields
=
array
(
$fields
);
        
}
    
        
if
( !
is_array
( reset(
$fields
) ) ) {
            
$fields
=
array
(
$fields
);
        
}
    
        
$this
->sqlFields =
$fields
;
        
return
$this
;
    
}
    
    
# 设置where条件;
    
public
function
where(
$where
=
''
) {
        
if
(
is_string
(
$where
) ) {
            
$where
=
array
(
$where
);
        
}
    
        
$this
->sqlWhere =
$where
;
        
return
$this
;
    
}
    
    
# 设置排序;
    
public
function
order(
$order
=
''
) {
        
if
(
is_string
(
$order
) ) {
            
$order
=
array
(
$order
);
        
}   
    
        
$this
->sqlOrder =
$order
;
        
return
$this
;
    
}
    
    
# 设置排序;
    
public
function
limit(
$limit
=
''
) {   
        
if
(
is_string
(
$limit
) ||
is_integer
(
$limit
) ) {
            
$limit
=
array
(
$limit
);
        
}
    
        
$this
->sqlLimit =
$limit
;
        
return
$this
;
    
}
    
    
# 连表方法;
    
public
function
join(
$on
=
''
) {
        
/*暂无*/
    
}
    
    
# 查询方法;
    
public
function
select() {
        
return
$this
->core(
'select'
);
    
}
    
    
# insert方法;
    
public
function
add(
$data 
=
''
) {
        
$this
->data =
$data
;
        
return
$this
->core(
'add'
);
    
}
    
    
# updata方法;
    
public
function
save(
$data
=
''
) {
        
$this
->data =
$data
;
        
return
$this
->core(
'save'
);
    
}
    
    
#
delete
方法;
    
public
function
delete
() {
        
return
$this
->core(
'delete'
);
    
}
    
    
# 预处理方法:
    
public
function
prepare() {
        
$var
= func_get_args();
        
if
(
count
(
$var
) < 1 )
return
$this
;
    
        
if
(
count
(
$this
->sqlTables ) <= 1 ) {
            
if
(
count
(
$var
) >= 1 && !
is_array
( reset(
$var
) ) ) {
                
$var
=
array
(
$var
);
            
}
        
}
    
        
if
(
count
(
$this
->sqlTables ) >1 && !
is_array
( reset(
$var
) ) ) {
            
exit
(
"预处理参数传入不正确!"
);
            
return
false;
        
}
    
        
# 取类型;
        
foreach
(
$var
as
$key
=>
$value
) {
            
$type
=
array_map
(
function
(
$v
){
                
return
substr
(
gettype
(
$v
),0,1);
            
},
$value
);
            
array_unshift
(
$var
[
$key
], implode(
$type
) );
        
}
    
        
$this
->sqlPrepare =
$var
;
        
return
$this
;
    
}
    
    
# 开启事务;
    
public
function
startTrans(
$flag
) {
        
if
( !
is_bool
(
$flag
) ) {
            
$this
->error =
'事务开启参数错误'
;
            
return
false;
        
}
        
return
$this
->db->autocommit( !
$flag
);
    
}
    
    
# 提交事务;
    
public
function
commit() {
        
$res
=
$this
->db->commit();
        
$this
->startTrans( false );
        
return
$res
;
    
}
    
    
# 回滚事务;
    
public
function
rollback() {
        
$res
=
$this
->db->rollback();
        
$this
->startTrans( false );
        
return
$res
;
    
}
    
    
# 核心方法;
    
private
function
core(
$action
) {
    
        
$tables
=
$this
->sqlTables;
    
        
if
(
empty
(
$tables
) ) {
            
$this
->error =
"未定义查询表;"
;
            
return
false;
        
}
    
        
switch
(
$action
) {
            
case
'select'
:
                    
                
$sql
=
$this
->build_select_sql();
                    
                
break
;
                
            
case
'save'
:
    
                
$data
=
$this
->get_write_data();
                    
                
if
( !
$data
) {
                    
return
false;
                
}
    
                
if
( false ===
$this
->check_where() ) {
                    
return
false;
                
}
    
                
$sql
=
$this
->build_update_sql(
$data
);
                    
                
break
;
    
            
case
'add'
:
                    
                
$data
=
$this
->get_write_data();
                    
                
if
( !
$data
) {
                    
return
false;
                
}
    
                
$sql
=
$this
->build_insert_sql(
$data
);
                    
                
break
;
                
            
case
'delete'
:
                    
                
if
( false ===
$this
->check_where() ) {
                    
return
false;
                
}
    
                
$sql
=
$this
->build_delete_sql();
    
                
break
;
        
}
    
        
if
(
count
(
$sql
) <= 1 ) {
    
            
$sql 
= reset(
$sql
);
                
            
if
(
is_array
(
$this
->sqlPrepare ) && !
empty
(
$this
->sqlPrepare  ) ) {
                
$result
=
$this
->execute(
$sql
);
            
}
else
{
                
$result
=
$this
->query(
$sql
);
            
}
                
        
}
else
{
                
            
if
(
is_array
(
$this
->sqlPrepare ) && !
empty
(
$this
->sqlPrepare  ) ) {
                
exit
(
'暂不支持多语句预处理;'
);
            
}
else
{
                
$result
=
$this
->multi_query(
$sql
);
            
}
        
}
    
        
if
( false ===
$result
) {
            
$this
->error =
$this
->db->error ?:
$this
->stmt->error;
            
return
false;
        
}
    
        
return
$this
->get_result(
$result
,
$action
);
    
    
}
    
    
# 构建sql语句;
    
private
function
build_select_sql( ) {
            
        
$tables
=
$this
->sqlTables;
        
$fields
=
$this
->sqlFields;
        
$where
=
$this
->sqlWhere;
        
$order
=
$this
->sqlOrder;
        
$limit
=
$this
->sqlLimit;
    
        
$sql
=
array
();
        
foreach
(
$tables
as
$key
=>
$table
) {
            
$sql_tmp
=
''
;
            
$sql_tmp
.=
'SELECT '
;
            
if
( !isset(
$fields
[
$key
] ) ) {
                 
$fields
[
$key
] =
'*'
;
            
}
            
if
(
is_array
(
$fields
[
$key
] ) ) {
                
array_walk
(
$fields
[
$key
],
function
( &
$v
) {
                    
$v
=
'`'
.
$v
.
'`'
;
                
});
                
$fields
[
$key
] = implode(
' , '
,
$fields
[
$key
] );
            
}
            
$sql_tmp
.=
$fields
[
$key
];
            
$sql_tmp
.=
' FROM '
.
'`'
.
$table
.
'`'
;
    
            
!
empty
(
$where
[
$key
] ) &&
$sql_tmp
.=
' WHERE '
.
$where
[
$key
];
            
!
empty
(
$order
[
$key
] ) &&
$sql_tmp
.=
' ORDER BY '
.
$order
[
$key
];
            
!
empty
(
$limit
[
$key
] ) &&
$sql_tmp
.=
' LIMIT '
.
$limit
[
$key
];
                
            
$sql
[
$key
] =
$sql_tmp
;
        
}
            
        
return
$sql
;
        
    
}
    
    
private
function
build_insert_sql(
$data
) {
        
$tables
=
$this
->sqlTables;
        
$sql
=
array
();
        
foreach
(
$tables
as
$key
=>
$table
) {
                
            
$sql_tmp
=
''
;           
            
$sql_tmp
.=
'INSERT INTO '
.
'`'
.
$table
.
'`'
;
                
            
$col
=
array_keys
(
$data
[
$key
] );
            
$callFunc
=
            
array_walk
(
$col
,
function
( &
$v
) {
                
$v
=
'`'
.
$v
.
'`'
;
            
} );           
            
$col
=
' ( '
.implode(
' , '
,
$col
).
' ) '
;
                
            
$val
=
array_values
(
$data
[
$key
] );           
            
array_walk
(
$val
,
function
( &
$v
) {
                
$v
=
$v
==
'?'
?
$v
:
'\''
.
$v
.
'\''
;
            
} );           
            
$val
=
' ( '
.implode(
' , '
,
$val
).
' ) '
;
                
            
$sql_tmp
.=
$col
;
            
$sql_tmp
.=
' VALUES '
.
$val
;
            
$sql
[
$key
] =
$sql_tmp
;
        
}
        
return
$sql
;
    
}
    
    
private
function
build_update_sql(
$data
) {
        
$tables
=
$this
->sqlTables;
        
$where
=
$this
->sqlWhere;
        
$sql
=
array
();
        
foreach
(
$tables
as
$key
=>
$table
) {
            
$sql_tmp
=
''
;
            
$sql_tmp
.=
'UPDATE '
.
'`'
.
$table
.
'`'
;
                
            
$set
=
array
();
    
            
foreach
(
$data
[
$key
]
as
$col
=>
$val
) {
                
$val
=
$val
==
'?'
?
$val
:
'\''
.
$val
.
'\''
;
                
$set
[] =
'`'
.
$col
.
'` = '
.
$val
;
            
}
            
$set
= implode(
' , '
,
$set
);
                
            
$sql_tmp
.=
' SET '
.
$set
;
            
$sql_tmp
.=
' WHERE '
.
$where
[
$key
];
            
$sql
[
$key
] =
$sql_tmp
;
        
}
        
return
$sql
;
    
}
    
    
private
function
build_delete_sql() {
        
$tables
=
$this
->sqlTables;
        
$where
=
$this
->sqlWhere;
        
$sql
=
array
();
        
foreach
(
$tables
as
$key
=>
$table
) {
            
$sql_tmp
=
''
;
            
$sql_tmp
.=
'DELETE FROM '
.
'`'
.
$table
.
'`'
;
            
$sql_tmp
.=
' WHERE '
.
$where
[
$key
];
            
$sql
[
$key
] =
$sql_tmp
;
        
}
        
return
$sql
;
    
}
    
    
# 单语句查询;
    
public
function
query(
$sql
) {
        
$this
->sql =
$sql
;
        
$this
->clean_attribute();
        
return
$this
->db->query(
$sql
);
    
}
    
    
# 单语句预查询;
    
public
function
execute(
$sql
,
$flag
= false ) {
    
        
$param
=
array_shift
(
$this
->sqlPrepare );
    
        
$result
=
$this
->db->prepare(
$sql
);
    
        
/*5.3是引用传递*/
        
if
(
strnatcmp
( phpversion(),
'5.3'
) >= 0 ) {
            
for
(
$i
= 0;
$i
<
count
(
$param
);
$i
++ ) {
                
$param
[
$i
] = &
$param
[
$i
];
            
}
        
}
    
        
@call_user_func_array(
array
(
$result
,
"bind_param"
),
$param
);
        
if
( !
$flag
) {
            
$this
->sql =
$sql
;
            
$this
->clean_attribute();
        
}
            
        
!
is_object
(
$this
->stmt  ) &&
$this
->stmt =
$result
;
            
        
return
$result
->execute();
    
    
}
    
    
# 多语句查询;
    
public
function
multi_query(
$sqlArr
) {
        
$sql
= implode(
';'
,
$sqlArr
);
        
$this
->sql =
$sql
;
        
$this
->clean_attribute();
        
return
$this
->db->multi_query(
$sql
);
    
}
        
    
# 获取结果集内容;
    
public
function
get_result(
$result
,
$action
) {
        
switch
(
$action
) {
            
case
'select'
:
                
$result
$this
->get_fetch_assoc(
$result
);
                
break
;
            
case
'add'
:
                
$result
$this
->get_insert_id();
                
break
;
            
case
'save'
:
                
$result
$this
->get_affected_rows();
                
break
;
            
case
'delete'
:
                
$result
$this
->get_affected_rows();
                
break
;
        
}
    
        
return
$result
;
    
    
}
    
    
# 将结果集转化为数组
    
public
function
get_fetch_assoc(
$result
=
''
) {
            
        
$res
=
array
();
        
$key
= 1;
        
do
{
                
            
if
(
is_object
(
$this
->stmt ) ) {
                
$result
=
$this
->stmt->get_result();
                
$this
->stmt =
''
;
            
}
else
{
                
$result
=
is_object
(
$result
) &&
$key
<= 1 ?
$result
:
$this
->db->store_result();
            
}
    
            
if
(
$result
) {
                
while
(
$row
=
$result
->fetch_assoc() ) {
                   
$res
[
$key
][] =
$row
;
                
}
                
$result
->free();
            
}   
                
            
$key
++;
    
        
}
while
(
$this
->db->more_results() &&
$this
->db->next_result() );
    
        
if
(
count
(
$res
) == 1 ) {
            
$res
= reset(
$res
);
        
}
    
        
return
$res
;
    
}
    
    
# 获取数据插入后的id
    
public
function
get_insert_id() {
        
$insertId
=
array
();
            
        
do
{
                
            
$insertId
[] =
$this
->db->insert_id;
            
        
}
while
(
$this
->db->more_results() &&
$this
->db->next_result() );
            
        
if
(
count
(
$insertId
) == 1 ) {
            
$insertId
= reset(
$insertId
);
        
}
            
        
return
$insertId
;
    
}
    
    
# 获取数据更新/删除的影响的行数;
    
public
function
get_affected_rows() {
        
$affectedRows
=
array
();
            
        
do
{
                
            
$affectedRows
[] =
$this
->db->affected_rows;
            
        
}
while
(
$this
->db->more_results() &&
$this
->db->next_result() );
    
        
if
(
count
(
$affectedRows
) == 1 ) {
            
$affectedRows
= reset(
$affectedRows
);
        
}
        
return
$affectedRows
;
    
}
    
    
# 获取写入数据;
    
private
function
get_write_data() {
        
$data
=
$this
->data;
    
        
if
( !
$data
|| !
is_array
(
$data
) ) {
            
$this
->error =
'数据非法!'
;
            
return
false;
        
}
            
        
if
(
count
(
$this
->sqlTables ) > 1 ) {
            
for
(
$i
= 0;
$i
<
count
(
$this
->sqlTables );
$i
++ ) {
                
if
( !
is_array
( current(
$data
) ) ) {
                    
$this
->error =
'需要写入的数据与数据表 数量不一致!'
;
                    
return
false;
                
}
            
}
            
return
$data
;
        
}
    
        
if
(
count
(
$this
->sqlTables ) == 1 &&
is_array
( reset(
$data
) ) ) {
            
return
$data
;
        
}
    
        
return
array
(
$data
);
    
}
    
    
# 增删改时 检查where
    
private
function
check_where() {
        
if
( !
$this
->sqlWhere ) {
            
$this
->error =
'没有条件,危险操作!'
;
            
return
false;
        
}
    
        
if
(
count
(
$this
->sqlWhere ) <
count
(
$this
->sqlTables ) ) {
            
$this
->error =
'条件与数据表 数量不一致! 危险!'
;
            
return
false;
        
}
    
        
return
true;
    
}
    
    
# 语句执行后清空部分属性;
    
private
function
clean_attribute(
$noRemove
=
array
(
'db'
,
'sqlTables'
,
'error'
,
'sql'
) ) {
        
$attributes
= get_class_vars( get_class(
$this
) );
        
foreach
(
$attributes
as
$key
=>
$value
) {
            
if
( !in_array(
$key
,
$noRemove
) ) {
                
$this
->
$key
=
''
;
            
}
        
}
    
}
    
    
# 获取最后执行的sql语句;
    
public
function
getLastSql() {
        
return
$this
->sql;
    
}
    
    
# 获取错误信息;
    
public
function
getError() {
        
return
$this
->error;
    
}
    
    
public
function
__destruct() {
        
$this
->db->close();
        
$this
->clean_attribute(
array
() );
    
}
    
}
    
    
// 测试
$config
=
array
(
    
'host'
=>
'localhost'
,
    
'user'
=>
'root'
,
    
'password'
=>
'admin'
,
    
'db'
=>
'test'
,
    
'charset'
=>
'utf8'
);
$M
=
new
db_mysqli(
$config
);
    
#单语句增删改查;
$data
=
array
(
'title'
=> time());
$res
=
$M
(
'title'
)->add(
$data
);
//返回ID号;
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
//INSERT INTO `title` ( `title` )  VALUES  ( '1407911896' );
    
$res
=
$M
(
'title'
)->field(
'title'
)->where(
'id > 2'
)->limit(10)->order(
'id desc'
)->select();
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
//SELECT `title` FROM `title` WHERE id > 2 ORDER BY id desc LIMIT 10;
    
    
    
$res
=
$M
(
'title'
)->where(
'id > 10'
)->
delete
();
//返回影响行数;
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
//DELETE FROM `title` WHERE id > 10;
    
#事务
$M
->startTrans( true );
    
$data
=
array
(
'title'
=>
'updat4e!'
);
$res
=
$M
(
'title'
)->where(
'id = 1'
)->save(
$data
);
//返回影响行数;
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
$M
->rollback();
    
    
#单语句预处理增删改查;
$data
=
array
(
'id'
=>
'?'
,
'title'
=>
'?'
);
$res
=
$M
(
'title'
)->prepare( 12,
'prepare'
)->add(
$data
);
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
    
$res
=
$M
(
'title'
)->where(
'id > ?'
)->prepare(5)->order(
'id desc'
)->select();
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
    
$res
=
$M
(
'title'
)->where(
'id > ? and title = ?'
)->prepare(
array
(9,
'update!'
))->
delete
();
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
    
$data
=
array
(
'title'
=>
'?'
);
$res
=
$M
(
'title'
)->where(
'id > ?'
)->prepare(
'update!'
, 6 )->save(
$data
);
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
    
#多语句查询 原有的参数变为数组;
$data
=
array
();
$data
[0] =
array
(
'title'
=>
'1'
.time());
$data
[1] =
array
(
'title'
=>
'2'
.time());
$tables
=
array
(
'title'
,
'title'
);
$res
=
$M
(
$tables
)->add(
$data
);
//返回ID号;
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
/*INSERT INTO `title` ( `title` )  VALUES  ( '11407913979' ) ;
INSERT INTO `title` ( `title` )  VALUES  ( '21407913979' )*/
    
$field
=
array
();
$field
[0] =
array
(
'title'
);
$field
[1] =
array
(
'id'
);
$res
=
$M
(
$tables
)->field(
$field
)->where(
array
(
'id > 5'
,
'id <= 5'
))->limit(10)->order(
'id desc'
)->select();
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
/*
SELECT `title` FROM `title` WHERE id > 5 ORDER BY id desc LIMIT 10;
SELECT * FROM `title` WHERE id <= 5
*/
    
$res
=
$M
(
$tables
)->where(
array
(
'id = 5'
,
'id = 6'
))->
delete
();
//返回影响行数;
var_dump(
$res
);
var_dump(
$M
->getLastSql() );
var_dump(
$M
->getError() );
/*
DELETE FROM `title` WHERE id = 5;
DELETE FROM `title` WHERE id = 6
*/