c5_labsci/zciyphp/db.php
2026-01-27 00:52:00 +08:00

328 lines
12 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/* =================================================================================
* License: GPL-2.0 license
* Author: 众产® https://ciy.cn/code
* Version: 0.6.11
* =================================================================================*/
/**
* 应用数据层类库(单服版)
* 注:单数据库服务器请用单服版,效率较高。多数据库服务器使用多服版。
* 1、type: mysql 使用MySQLi引擎 (不再支持)
* type: pdo 使用PDO引擎
* type: http 使用http透传不再支持
*
* 2、mode: db.php [单服版]
* dbns.php [多服版] 读写分离,一主多从模式。
* dbms.php [多服版] 多写多读模式。从注册中心获取一台空闲读服务器。
*
* getone 获取一条数据。 无数据返回null 出错返回false 判断is_array确认数据有效
* get1 获取第一行第一列数据 无数据返回null 出错返回false
* get 获取数据集合。 无数据返回array() 出错返回false
* getraw 原始方法获取数据集合。 无数据返回array() 出错返回false
* insert 新增数据。 成功返回影响行数 出错返回false
* update 更新数据。 成功返回影响行数 出错返回false
* delete 删除及备份数据。 成功返回影响行数 出错返回false
* execute 执行SQL语句。 成功返回影响行数 出错返回false
* begin 开始事务 成功返回true 出错返回false
* commit 事务提交 成功返回true 出错返回false
* rollback 事务回滚 成功返回true 出错返回false
* tran 事务回调 成功返回true 出错返回false
* getfield 获取表字段注解 返回字段名称字符串,引用返回注解
* getdbcodes 获取表内某字段代码数组 无数据返回array()
* insert_id 获取刚新增数据的id
* errdata 错误集中接收后返回
*
* 变量名取名尽量用s尾缀区分建议getone函数使用$xxrowget函数使用$xxrows。
*/
namespace ciy;
class db { //单数据库版
public $linkdb; //写服务器驱动层类实例。
public $dbpst;
public $error;
public $pf;
public $lock;
function __construct($dbpst = '') {
$this->linkdb = false;
$this->dbpst = $dbpst;
$this->error = '';
$this->lock = false;
}
/**
* 连接到服务器。
*/
function connect() {
if ($this->linkdb !== false)
return $this->linkdb;
$cfg = webini('db' . $this->dbpst);
if (is_string($cfg))
die($cfg);
$this->linkdb = new pdo($cfg, $this->pf);
$this->linkdb->connect();
return $this->linkdb;
}
/**
* 获取一条数据。
* 返回array()无数据返回null出错返回false
* csql SQL拼接类
* 例:
* $csql = new \ciy\sql();
* $csql->...
* $row = $mydata->getone($csql);
* if(is_array($row))
* $row['username']...
*/
function getone($csql) {
$limit = $csql->limit;
if (empty($limit))
$limit = ' limit 1';
if ($this->lock)
$limit .= ' for update';
$ret = $this->connect()->get(2, $csql->buildsql() . $limit, $csql->tsmt);
if ($ret === false || $ret === null)
return $this->errdata($ret);
return $ret;
}
/**
* 获取一条数据的单个字段。
* 返回变量无数据返回null出错返回false
* csql SQL拼接类
* 例:
* $csql = new \ciy\sql();
* $usercount = toint($mydata->get1($csql));
* $csql->column('name');
* $username = $mydata->get1($csql);
*/
function get1($csql) {
if ($csql->column == '*')
$csql->column = 'count(*)';
$limit = $csql->limit;
if (empty($limit))
$limit = ' limit 1';
if ($this->lock)
$limit .= ' for update';
$ret = $this->connect()->get(3, $csql->buildsql() . $limit, $csql->tsmt);
if ($ret === false || $ret === null)
return $this->errdata($ret);
return $ret;
}
/**
* 获取数据集合。
* 返回array()出错返回false
* 判断is_array确认数据有效
* csql SQL拼接类
* pageno 第pageno页不分页传null默认null
* pagecount 每页pagecount条默认20
* rowcount 返回总数据条数(数据量大,查询耗时较高),不填不查询。
* 例:
* $rows = $mydata->get($csql);//查询全部数据
* $rows = $mydata->get($csql,1,$pagecount,$rowcount);
* if(is_array($rows)){
* foreach($rows as $row)
* $row['username']...
* }
*/
function get($csql, &$rowcount = 0) { //$pageno=null 查询全部
$sql = $csql->buildsql();
$limit = $csql->limit;
if ($this->lock)
$limit .= ' for update';
$ret = $this->connect()->get(1, $sql . $limit, $csql->tsmt);
if ($ret === false)
return $this->errdata($ret);
if ($rowcount == -1) {
$column = $csql->column;
$csql->column = 'count(*)';
$rowcount = toint($this->connect()->get(3, $csql->buildsql(), $csql->tsmt));
$csql->column = $column;
}
return $ret;
}
/**
* 原始参数获取数据集合。
* 返回array()出错返回false
* sql SQL prepare字符串
* tsmt array ?对应数据集
* 例:
* $row = $mydata->getraw('select * from xxx where id=?',[3]);
*/
function getraw($sql, $tsmt = array()) {
$ret = $this->connect()->get(1, $sql, $tsmt);
if ($ret === false)
return $this->errdata($ret);
return $ret;
}
function getfield(&$field, $table) {
$fieldrows = $this->connect()->get(1, 'show full fields from ' . $table, array());
if ($fieldrows === false)
return $this->errdata($fieldrows);
$sorts = array();
foreach ($fieldrows as $fr) {
if (!empty($fr['Comment']))
$sorts[] = $fr['Field'];
$field[$fr['Field']] = array('c' => $fr['Comment']);
}
return implode(',', $sorts);
}
function getdbcodes($table, $field) {
$fieldrow = $this->connect()->get(1, 'show full fields from ' . $table . ' where Field=?', array($field));
if (count($fieldrow) == 0)
return array();
$comment = $fieldrow[0]['Comment'];
$ret = array();
$ind = strpos($comment, ',TINT');
if ($ind !== false) {
$exts = explode('|', substr($comment, $ind + 6));
$exts = explode('.', $exts[0]);
for ($i = 0; $i < count($exts); $i++) {
$excos = explode(':', $exts[$i]);
if (count($excos) > 1) {
$ret[] = array('id' => $excos[0], 'name' => $excos[1]);
} else if (!empty($excos[0])) {
$ret[] = array('id' => $i, 'name' => $excos[0]);
}
}
return $ret;
}
$ind = strpos($comment, ',TBIN');
if ($ind !== false) {
$exts = explode('|', substr($comment, $ind + 6));
$exts = explode('.', $exts[0]);
for ($i = 0; $i < count($exts); $i++) {
$excos = explode('.', $exts[$i]);
$ret[] = array('id' => $i + 1, 'name' => $exts[$i]);
}
return $ret;
}
$ind = strpos($comment, ',BOOL');
if ($ind !== false) {
$exts = explode('.', substr($comment, $ind + 6));
if (count($exts) == 1)
$exts[1] = '';
$ret[] = array('id' => 1, 'name' => empty($exts[0]) ? '✔' : $exts[0]);
$ret[] = array('id' => 2, 'name' => empty($exts[1]) ? '✘' : $exts[1]);
return $ret;
}
return $ret;
}
function insert_id() {
return $this->connect(true)->insert_id();
}
function insert($csql, $updata) {
$ret = $this->connect(true)->insert($csql, $updata);
if ($ret === false)
return $this->errdata($ret);
return $ret;
}
function update($csql, $updata) {
$ret = $this->connect(true)->update($csql, $updata);
if ($ret === false)
return $this->errdata($ret);
return $ret;
}
/**
* 删除表数据支持备份到_bak。注意_bak建表时应去掉id的自增属性
* 成功返回影响行数失败返回false
* csql SQL拼接类
* backup false:直接删除true先备份到table_bak再删除。
* 例:
* $affected = $mydata->delete($csql,true);//备份后删除
*/
function delete($csql, $backup = false) {
if ($backup) {
$fields = $this->connect(true)->get(1, 'show full fields from ' . $csql->table, array());
$fieldlts = array();
if ($fields === false)
return $this->errdata($fields);
foreach ($fields as $row)
$fieldlts[] = $row['Field'];
$fieldlt = implode(',', $fieldlts);
$sql = "insert into {$csql->table}_bak ({$fieldlt}) select {$fieldlt} from {$csql->table}" . $csql->buildwhere();
$ret = $this->connect(true)->execute($sql, $csql->tsmt);
if ($ret === false)
return $this->errdata($ret);
}
$ret = $this->connect(true)->execute("delete from {$csql->table}" . $csql->buildwhere(), $csql->tsmt);
if ($ret === false)
return $this->errdata($ret);
return $ret;
}
/**
* 执行SQL语句。
* 成功返回影响行数失败返回false
* sql SQL语句。
* 例:
* $affected = $mydata->execute('update users set username=? where id=?',['aaa',12]);
*/
function execute($sql, $tsmt = array()) {
$ret = $this->connect(true)->execute($sql, $tsmt);
if ($ret === false)
return $this->errdata($ret);
return $ret;
}
function begin() {
$ret = $this->connect(true)->begin();
if ($ret === false)
return $this->errdata($ret);
$this->lock = true;
return $ret;
}
function commit() {
$ret = $this->connect(true)->commit();
if ($ret === false)
return $this->errdata($ret);
$this->lock = false;
_setmemvar($this, 'func_commit', array('params+1'));
return $ret;
}
function rollback() {
$ret = $this->connect(true)->rollback();
if ($ret === false)
return $this->errdata($ret);
$this->lock = false;
_setmemvar($this, 'func_rollback', array('params+1'));
return $ret;
}
function tran($func) {
if (!($func instanceof \Closure)) {
$this->error = '没有传递正确的闭包函数';
return false;
}
$this->begin();
$ret = false;
try {
$ret = $func();
} catch (\Exception $ex) {
$ret = false;
$this->error = $ex->getMessage();
}
if ($ret === false)
$this->rollback();
else
$this->commit();
return $ret;
}
function errdata($ret) {
if ($this->linkdb !== false)
$this->error = $this->linkdb->error;
return $ret;
}
function trace($pf, $rsuser = null) { //traceid全链路跟踪
if (!preg_match('/^[A-Z]{2}\d{13}_\d{8}$/', $pf)) //防止前端攻击
$pf = 'ER' . time() . '000_' . rand(10000000, 99999999);
$time = substr($pf, 2, 10);
if (abs(time() - $time) > 10) //跟随服务器时间
$pf .= ',svrt=' . time();
if (is_array($rsuser))
$this->pf = $pf . ',ip=' . getip() . ',uid=' . $rsuser['id'];
else
$this->pf = $pf . ',ip=' . getip() . ',uid=no';
}
function __destruct() {
}
}