Files
BESCMS/dayrui/Fcms/Core/Model.php
T

2102 lines
63 KiB
PHP
Raw 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 namespace Phpcmf;
/**
* https://www.besyun.com
* BESCMS
* 本文件是框架系统文件,二次开发时不可以修改本文件
**/
if (is_file(MYPATH.'Extend/Model.php')) {
require MYPATH.'Extend/Model.php';
} else {
require FRAMEPATH.'Extend/Model.php';
}
// 模型类
class Model {
public $db;
public $prefix;
public $id = 'id';
public $key = 'id';
public $site;
public $field;
public $siteid;
public $table;
public $mytable;
public $stable; // join关联表
public $sfield; // join关联表的字段
public $db_temp; // 备份默认数据库
public $uid;
public $admin;
public $member;
protected $date_field;
protected $param;
protected $init;
public function __construct() {
list($this->db, $this->prefix) = \Frame\Model::_load_db();
$this->uid = \Phpcmf\Service::C()->uid;
$this->site = \Phpcmf\Service::C()->site;
$this->admin = \Phpcmf\Service::C()->admin;
$this->member = \Phpcmf\Service::C()->member;
$this->siteid = defined('SITE_ID') ? SITE_ID : 0;
}
// 设置初始化查询条件
public function init($data) {
isset($data['id']) && $this->id = $this->key = $data['id'];
isset($data['table']) && $this->table = $data['table'];
isset($data['stable']) && $this->stable = $data['stable'];
isset($data['sfield']) && $this->sfield = $data['sfield'];
isset($data['field']) && $this->field = $data['field'];
isset($data['date_field']) && $this->date_field = $data['date_field'];
isset($data['order_by']) && $this->param['order_list'] = $data['order_by'];
isset($data['group_by']) && $this->param['group_list'] = $data['group_by'];
isset($data['order_list']) && $this->param['order_list'] = $data['order_list'];
isset($data['where_list']) && $this->param['where_list'] = $data['where_list'];
isset($data['is_diy_where_list']) && $this->param['is_diy_where_list'] = $data['is_diy_where_list'];
isset($data['join_list']) && $this->param['join_list'] = $data['join_list'];
isset($data['select_list']) && $this->param['select_list'] = $data['select_list'];
$this->init = $data; // 方便调用
return $this;
}
// 设置列表搜索条件
public function set_where_list($where) {
$this->param['where_list'] = $where;
}
// 追加列表搜索条件
public function add_where_list($where) {
$this->param['where'][] = $where;
}
// 设置操作主键
public function id($id = '') {
if ($id) {
$this->key = $id;
} else {
$this->key = $this->id;
}
return $this;
}
// 设置数据源
public function db_source($name = '') {
if ($name) {
$this->db_temp = $this->db;
list($this->db, $this->prefix) = \Frame\Model::_load_db_source($name);
}
return $this;
}
// 设置操作表
public function table($name) {
$this->table = $name;
return $this;
}
// 设置操作站点的表
public function table_site($name, $site = 0) {
if (!$site) {
$site = $this->siteid ? $this->siteid : SITE_ID;
}
$this->table = dr_site_table_prefix($name, $site);
return $this;
}
// 获取表前缀
public function dbprefix($name = '') {
return $this->prefix.$name;
}
// 执行sql
public function query($sql) {
if (!$this->db->simpleQuery($sql)) {
$error = $this->db->error();
$this->_clear();
log_message('error', $sql.': '.$error['message'].'<br>'.FC_NOW_URL);
return $this->_return_error($error['message']);
}
$this->_clear();
return dr_return_data(1);
}
// 附表不存在时创建附表
public function is_data_table($table, $tid) {
if ($tid > 0 && !$this->is_table_exists($this->dbprefix($table.$tid))) {
// 附表不存在时创建附表
list($a, $sql, $name) = \Phpcmf\Service::M('table')->create_table_sql($this->dbprefix($table).'0');
$this->query(str_replace(
[$name, 'CREATE TABLE '],
[$this->dbprefix($table.$tid), 'CREATE TABLE IF NOT EXISTS '],
$a
));
}
$this->_clear();
}
// 表是否存在
public function is_table_exists($table) {
if (!$table) {
$this->_clear();
return 0;
}
$table = strpos($table, $this->prefix) === 0 ? $table : $this->dbprefix($table);
$rt = $this->db->tableExists($table) ? 1 : 0;
$this->_clear();
return $rt;
}
// 表字段是否存在
public function is_field_exists($table, $name) {
if (!$table || !$name) {
$this->_clear();
return 0;
}
$table = strpos($table, $this->prefix) === 0 ? $table : $this->dbprefix($table);
$rt = $this->db->fieldExists($name, $table) ? 1 : 0;
$this->_clear();
return $rt;
}
// 字段值是否存在
public function is_exists($id, $name, $value) {
$builder = $this->db->table($this->table);
// 条件
if ($this->param['where']) {
foreach ($this->param['where'] as $v) {
dr_count($v) == 2 ? $builder->where($v[0], $v[1]) : $builder->where($v, null, false);
}
}
// in条件
if ($this->param['where_in']) {
foreach ($this->param['where_in'] as $v) {
dr_count($v) == 2 ? $builder->whereIn($v[0], $v[1]) : $builder->whereIn($v, null, false);
}
}
$rt = $builder->where($name, $value)->where($this->key.'<>'. $id)->countAllResults();
$this->_clear();
return $rt;
}
// 统计数量
public function counts($table = '', $where = '') {
$table = !$table ? $this->table : $table;
if (!$table) {
return 0;
}
$builder = $this->db->table($table);
// 条件
if ($this->param['where']) {
foreach ($this->param['where'] as $v) {
dr_count($v) == 2 ? $builder->where($v[0], $v[1]) : $builder->where($v, null, false);
}
}
// in条件
if ($this->param['where_in']) {
foreach ($this->param['where_in'] as $v) {
dr_count($v) == 2 ? $builder->whereIn($v[0], $v[1]) : $builder->whereIn($v, null, false);
}
}
// 分组
$this->param['group'] && $builder->groupBy($this->param['group']);
$where && $builder->where($where);
$this->_clear();
return $builder->countAllResults();
}
// 插入数据
public function insert($data) {
$this->db->table($this->table)->insert($data);
$rt = $this->db->error();
if ($rt['code']) {
$this->_clear();
log_message('error', $this->table.': '.$rt['message'].'<br>'.FC_NOW_URL);
return $this->_return_error($this->table.': '.$rt['message']);
}
$id = $this->db->insertID();
!$id && $id = intval($data[$this->key]);
if (!$id) {
$this->_clear();
log_message('debug', $this->table.': 主键获取失败<br>'.FC_NOW_URL);
return $this->_return_error($this->table.': 主键获取失败');
}
$this->_clear();
return dr_return_data($id);
}
// 插入数据
public function replace($data) {
$this->db->table($this->table)->replace($data);
$rt = $this->db->error();
if ($rt['code']) {
$this->_clear();
log_message('error', $this->table.': '.$rt['message'].'<br>'.FC_NOW_URL);
return $this->_return_error($this->table.': '.$rt['message']);
}
$id = $this->db->insertID();
!$id && $id = intval($data[$this->key]);
if (!$id) {
$this->_clear();
log_message('debug', $this->table.': 主键获取失败<br>'.FC_NOW_URL);
return $this->_return_error($this->table.': 主键获取失败');
}
$this->_clear();
return dr_return_data($id);
}
// 批量插入
public function insert_batch($data) {
if (!$this->table || !$data) {
return;
}
$rt = $this->db->table($this->table)->insertBatch($data);
$this->_clear();
return $rt;
}
// 批量更新
public function update_batch($data, $key = 'id') {
if (!$this->table || !$data) {
return;
}
$this->db->table($this->table)->updateBatch($data, $key ? $key : $this->key);
$this->_clear();
}
// 更新数据
public function update($id, $data, $where = '') {
if (!$data) {
$this->_clear();
return $this->_return_error($this->table.': update() data值为空');
}
$db = $this->db->table($this->table);
$id && $db->where($this->key, (int)$id);
$where && $db->where($where, null, false);
// 条件
if ($this->param['where']) {
foreach ($this->param['where'] as $v) {
dr_count($v) == 2 ? $db->where($v[0], $v[1]) : $db->where($v, null, false);
}
}
// in条件
if ($this->param['where_in']) {
foreach ($this->param['where_in'] as $v) {
dr_count($v) == 2 ? $db->whereIn($v[0], $v[1]) : $db->whereIn($v, null, false);
}
}
$db->update($data);
$rt = $this->db->error();
if ($rt['code']) {
$this->_clear();
log_message('error', $this->table.': '.$rt['message'].'<br>'.FC_NOW_URL);
return $this->_return_error($this->table.': '.$rt['message']);
}
$this->_clear();
return dr_return_data($id);
}
// 删除数据
/*
* 主键
* */
public function delete($id = 0 , $where = '') {
$db = $this->db->table($this->table);
$where && $db->where($where, null, false);
$id && $db->where($this->key, (int)$id);
// 条件
if ($this->param['where']) {
foreach ($this->param['where'] as $v) {
dr_count($v) == 2 ? $db->where($v[0], $v[1]) : $db->where($v, null, false);
}
}
// in条件
if ($this->param['where_in']) {
foreach ($this->param['where_in'] as $v) {
dr_count($v) == 2 ? $db->whereIn($v[0], $v[1]) : $db->whereIn($v, null, false);
}
}
// 执行删除
$db->delete();
$rt = $this->db->error();
if ($rt['code']) {
$this->_clear();
log_message('error', $this->table.': '.$rt['message'].'<br>'.FC_NOW_URL);
return $this->_return_error($this->table.': '.$rt['message']);
}
$this->_clear();
return dr_return_data(1);
}
// 执行”写入”类型的语句(insert,update等)时返回有多少行受影响
public function affected_rows() {
return $this->db->affectedRows();
}
// 启动事务
public function trans_start(){
$this->db->transBegin();
}
// 回滚事务
public function trans_rollback(){
$this->db->transRollback();
}
// 执行事务提交
public function trans_comment(){
if ($this->db->transStatus() === FALSE) {
$this->db->transRollback();
return false;
} else {
$this->db->transCommit();
return true;
}
}
// 删除全部内容
public function clear_all() {
return $this->db->table($this->table)->truncate();
}
// 批量删除数据
/*
* 主键数组
* */
public function delete_all($ids, $where = '') {
$this->deleteAll($ids, $where);
}
public function deleteAll($ids, $where = '') {
$db = $this->db->table($this->table);
$where && $db->where($where, null, false);
// 条件
if ($this->param['where']) {
foreach ($this->param['where'] as $v) {
dr_count($v) == 2 ? $db->where($v[0], $v[1]) : $db->where($v, null, false);
}
}
// in条件
if ($this->param['where_in']) {
foreach ($this->param['where_in'] as $v) {
dr_count($v) == 2 ? $db->whereIn($v[0], $v[1]) : $db->whereIn($v, null, false);
}
}
$db->whereIn($this->key, (array)$ids)->delete();
$rt = $this->db->error();
if ($rt['code']) {
$this->_clear();
log_message('error', $this->table.': '.$rt['message'].'<br>'.FC_NOW_URL);
return $this->_return_error($this->table.': '.$rt['message']);
}
$this->_clear();
return dr_return_data(1);
}
/*
* 保存单个数据
* 主键
* 字段名
* 字段值
* */
public function save($id, $name, $value, $where = '') {
$db = $this->db->table($this->table);
$where && $db->where($where, null, false);
$db->where($this->key, (int)$id)->update([$name => $value]);
$rt = $this->db->error();
if ($rt['code']) {
$this->_clear();
return $this->_return_error($this->table.': '.$rt['message']);
}
$this->_clear();
return dr_return_data($id);
}
/*
* 获取单个数据
* 主键
* */
public function get($id) {
$query = $this->db->table($this->table)->where($this->key, (int)$id)->get();
if (!$query) {
$this->_clear();
return [];
}
$rt = $query->getRowArray();
$this->_clear();
return $rt;
}
/*
* 获取全部数据
* 指定数量
* 数组主键id
* */
public function get_all($num = 0, $key = '') {
return $this->getAll($num, $key);
}
public function getAll($num = 0, $key = '') {
$builder = $this->db->table($this->table);
// 条件
if ($this->param['where']) {
foreach ($this->param['where'] as $v) {
dr_count($v) == 2 ? $builder->where($v[0], $v[1]) : $builder->where($v, null, false);
}
}
// in条件
if ($this->param['where_in']) {
foreach ($this->param['where_in'] as $v) {
dr_count($v) == 2 ? $builder->whereIn($v[0], $v[1]) : $builder->whereIn($v, null, false);
}
}
// select字段
$this->_apply_builder_select($builder);
// 排序
$this->param['order'] && $builder->orderBy($this->param['order']);
// 分组
$this->param['group'] && $builder->groupBy($this->param['group']);
// 数量控制
if ($this->param['limit']) {
list($a, $b) = explode(',', $this->param['limit']);
if ($b) {
$builder->limit($a, $b);
} else {
$builder->limit($a);
}
} elseif ($num) {
$builder->limit($num);
}
$query = $builder->get();
if (!$query) {
$this->_clear();
return [];
}
$rt = $query->getResultArray();
if ($rt && $key) {
$rt2 = $rt;
$rt = [];
foreach ($rt2 as $i => $t) {
$rt[(isset($t[$key]) ? $t[$key] : $i)] = $t;
}
}
$this->_clear();
return $rt;
}
/*
* 获取单个数据
* */
public function getRow() {
$builder = $this->db->table($this->table);
// 条件
if ($this->param['where']) {
foreach ($this->param['where'] as $v) {
dr_count($v) == 2 ? $builder->where($v[0], $v[1]) : $builder->where($v, null, false);
}
}
// in条件
if ($this->param['where_in']) {
foreach ($this->param['where_in'] as $v) {
dr_count($v) == 2 ? $builder->whereIn($v[0], $v[1]) : $builder->whereIn($v, null, false);
}
}
// select字段
$this->_apply_builder_select($builder);
if (!$builder) {
$this->_clear();
return [];
}
// 排序
$this->param['order'] && $builder->orderBy($this->param['order']);
// 分组
$this->param['group'] && $builder->groupBy($this->param['group']);
$builder->limit(1);
$rt = $builder->get();
$data = [];
$rt && $data = $rt->getRowArray();
$this->_clear();
return $data;
}
/*
* 获取单个字段值
* */
public function getField($name) {
$data = $this->getRow();
return isset($data[$name]) ? $data[$name] : '';
}
/*
* 操作数据
* 数据不存在-1, 变更值0, 变更至1
* */
public function used($id, $name) {
$data = $this->db->table($this->table)->select($name)->where('id', (int)$id)->get()->getRowArray();
if ($data) {
$value = $data[$name] ? 0 : 1;
// 更新
$this->db->table($this->table)->where('id', $id)->update([$name => $value]);
$this->_clear();
return $value;
}
$this->_clear();
return -1;
}
/////////////////////////////////////////////////////////////////////////
// 条件组合(按字段类型分发到 where_field_*
public function _where($table, $name, $value, $field, $is_like = false) {
if (!$value && dr_strlen($value) == 0) {
return ''; //空值
}
$name = dr_safe_replace($name, ['\\', '/']);
$ft = isset($field['fieldtype']) ? $field['fieldtype'] : '';
if ($ft == 'Date' || in_array($name, ['inputtime', 'updatetime'])) {
list($s, $e) = explode(',', (string) $value);
$s = (int) strtotime((string) $s);
$e = (int) strtotime((string) $e);
if ($s == $e && $s == 0) {
return '';
}
$col = $this->_where_field_col($table, $name);
// 无结束日期:开区间(各库语法一致,不必走驱动)
if (!$e) {
return $col.' > '.$s;
}
return $this->where_between($col, $s, $e);
}
if ($ft == 'File' && isset($field['fieldname']) && $field['fieldname'] == 'thumb' && $value == 1) {
return $this->where_field_thumb($table, $name, $value);
}
if ($ft && strpos($ft, 'map') !== false) {
return $this->where_field_map($table, $name, $value);
}
if ($ft == 'Diy'
&& !empty($field['setting']['option']['file'])
&& function_exists('dr_diy_field_'.substr($field['setting']['option']['file'], 0, -4).'_search')) {
return $this->where_field_diy($table, $name, $value, $field);
}
if ($ft == 'Linkage') {
return $this->where_field_linkage($table, $name, $value, $field, $is_like);
}
if ($ft == 'Linkages') {
return $this->where_field_linkages($table, $name, $value, $field, $is_like);
}
if (in_array($ft, ['Selects', 'Checkbox', 'Cats'])) {
return $this->where_field_checkbox($table, $name, $value, $field, $is_like);
}
if (in_array($ft, ['Members', 'Related'])) {
return $this->where_field_members($table, $name, $value);
}
if (in_array($ft, ['Radio', 'Select'])) {
return $this->where_field_select($table, $name, $value, $field, $is_like);
}
if (substr_count($value, ',') == 1 && preg_match('/[\+\-0-9\.]+,[\+\-0-9\.]+/', $value)) {
list($s, $e) = explode(',', (string) $value);
$s = floatval($s);
$e = floatval($e);
$col = $this->_where_field_col($table, $name);
if ($s == $e && $s == 0) {
return $col.' = 0';
}
if (!$e && $s > 0) {
return $col.' > '.$s;
}
if (!$e) {
$e = 0;
}
return $this->where_between($col, $s, $e);
}
if ($is_like || strpos($value, '%') !== false || strpos($value, ' ') !== false) {
return $this->where_field_like($table, $name, $value);
}
return $this->where_field_eq($table, $name, $value);
}
protected function _limit_where(&$select, $param, $field, $table) {
$table = $this->dbprefix($table);
if (isset($param['keyword']) && $param['keyword']) {
$param['keyword'] = htmlspecialchars(urldecode($param['keyword']));
}
$fname = $param['field'];
$kw = $param['keyword'];
$finfo = isset($field[$fname]) && is_array($field[$fname]) ? $field[$fname] : [];
$ft = isset($finfo['fieldtype']) ? $finfo['fieldtype'] : '';
if ($fname == $this->id) {
$sql = $this->where_limit_id($table, $this->id, $kw);
} elseif (!empty($finfo['myfunc'])) {
$sql = $this->where_limit_myfunc($param, $finfo);
} elseif ($fname == 'uid' || $ft == 'Uid') {
$sql = $this->where_limit_uid($table, $fname, $kw);
} elseif ($ft == 'INT' || !empty($finfo['isint'])) {
$sql = $this->where_limit_int($table, $fname, $kw);
} elseif (!empty($finfo['isemoji'])) {
$sql = $this->where_limit_emoji($table, $fname, $kw);
} elseif (!empty($finfo['iswhere'])) {
$sql = $this->where_limit_eq($table, $fname, $kw);
} else {
$sql = $this->_where($table, $fname, $kw, $finfo, true);
}
if ($sql !== null && $sql !== '') {
$select->where($sql, null, false);
}
return $select;
}
/**
* 日期字符串转时间戳(无时分秒时:开始补 00:00:00,结束补 23:59:59
*/
protected function _limit_date_to_time($date, $is_end = false) {
$date = trim((string) $date);
if ($date === '') {
return $is_end ? SYS_TIME : 1;
}
if (strpos($date, ' ') === false) {
$date .= $is_end ? ' 23:59:59' : ' 00:00:00';
}
return (int) strtotime($date);
}
/**
* 条件查询
*
* @param object $select 查询对象
* @param intval $where 是否搜索
* @return intval
*/
protected function _limit_page_where(&$select, $param) {
// 默认搜索条件
$this->param['where_list'] && $select->where($this->param['where_list']);
// 默认搜索条件 关联查询
$this->param['join_list'] && $select->join(
$this->param['join_list'][0],
$this->param['join_list'][1],
$this->param['join_list'][2]
);
// 定义的条件
if ($this->param['where']) {
foreach ($this->param['where'] as $v) {
dr_count($v) == 2 ? $select->where($v[0], $v[1]) : $select->where($v, null, false);
}
}
// 条件搜索
if ($param) {
$field = $this->field;
$field[$this->id] = $this->id;
// 关键字 + 自定义字段搜索
if (isset($param['keyword']) && $param['keyword'] != '') {
if (isset($this->init['is_swhere']) && $this->init['is_swhere']) {
if (isset($this->sfield[$param['field']]) && $this->stable) {
$select = $this->_limit_where($select, $param, $this->sfield, $this->stable);
} elseif (isset($field[$param['field']])) {
$select = $this->_limit_where($select, $param, $field, $this->table);
}
} else {
if (isset($field[$param['field']])) {
$select = $this->_limit_where($select, $param, $field, $this->table);
} elseif (isset($this->sfield[$param['field']]) && $this->stable) {
$select = $this->_limit_where($select, $param, $this->sfield, $this->stable);
}
}
}
// 时间搜索(date_form / date_to → BETWEEN
if ($this->date_field) {
$date_form = isset($param['date_form']) ? trim((string) $param['date_form']) : '';
$date_to = isset($param['date_to']) ? trim((string) $param['date_to']) : '';
if ($date_form !== '' || $date_to !== '') {
if ($date_form !== '') {
$start = max($this->_limit_date_to_time($date_form, false), 1);
$end = $date_to !== '' ? $this->_limit_date_to_time($date_to, true) : SYS_TIME;
} else {
$start = 1;
$end = $this->_limit_date_to_time($date_to, true);
}
$sql = $this->where_between($this->date_field, $start, $end);
if ($sql) {
$select->where($sql, null, false);
}
}
}
// 栏目查询
if (isset($param['catid']) && $param['catid'] && function_exists('dr_cat_value')) {
$mid = defined('MOD_DIR') ? MOD_DIR : (APP_DIR ? APP_DIR : 'share');
$cat = dr_cat_value($mid, $param['catid']);
$cat && $cat['child'] ? $select->whereIn('catid', explode(',', $cat['childids'])) : $select->where('catid', (int)$param['catid']);
}
// 其他自定义字段查询
if (isset($this->param['is_diy_where_list']) && $this->param['is_diy_where_list']) {
$where = [];
foreach ($param as $i => $v) {
if (!in_array($i, ['id', 'keyword', 'catid', 'date_form', 'date_to', 'field', 'total']) && isset($field[$i]) && $field[$i]['ismain'] && strlen($v)) {
$where[] = str_replace('`{finecms_table}`.', '', $this->_where('{finecms_table}', $i, $v, $field));
}
}
$where && $select->where(implode(' AND ', $where), null, false);
}
}
return $param;
}
// 分页
public function limit_page($size = SYS_ADMIN_PAGESIZE, $where = '') {
$page = max(1, (int)\Phpcmf\Service::L('input')->get('page'));
$total = (int)\Phpcmf\Service::L('input')->get('total');
$param = \Phpcmf\Service::L('input')->get();
unset($param['s'], $param['c'], $param['m'], $param['d'], $param['page']);
if (isset($param['keyword']) && $param['keyword']) {
$param['keyword'] = trim(urldecode($param['keyword']));
}
if ($size > 0 && !$total) {
$select = $this->db->table($this->table);
if ($this->param['group_list']) {
$select->select('count(DISTINCT '.$this->param['group_list'].') as total');
} else {
$select->select('count(*) as total');
}
// 自定义查询闭包函数
if (isset($this->init['select_function'])) {
$this->init['select_function']($select);
}
$where && $select->where($where);
$param = $this->_limit_page_where($select, $param);
$query = $select->get();
if (!$query) {
log_message('debug', '数据查询失败:'.$this->table);
$this->_clear();
return [[], $total, $param];
}
$data = $query->getRowArray();
$total = (int)$data['total'];
$param['total'] = $total;
unset($select);
if (!$total) {
$this->_clear();
return [[], $total, $param];
}
}
$select = $this->db->table($this->table);
$this->param['select_list'] && $select->select($this->param['select_list']);
// 自定义查询闭包函数
if (isset($this->init['select_function'])) {
$this->init['select_function']($select);
}
$where && $select->where($where);
$param = $this->_limit_page_where($select, $param);
if ($size > 0) {
$select->limit($size, intval($size * ($page - 1)));
}
$this->param['group_list'] && $select->groupBy($this->param['group_list']);
//分析参数合法性
$order = isset($param['order']) && $param['order'] ? urldecode($param['order']) : ''; // 获取的排序参数
$order_str = dr_safe_replace($this->param['order_list']);
if ($order) {
$arr = explode(',', $order);
$order_arr = [];
foreach ($arr as $t) {
list($order_field, $b) = explode(' ', $t);
if ($this->is_field_exists($this->table, $order_field)) {
if ($this->stable && $this->is_field_exists($this->stable, $order_field)) {
// 两个表都有这个字段
$order_arr[] = $this->table.'.'.$order_field.' '.($b && $b=='asc' ? 'asc' : 'desc');
} else {
$order_arr[] = $order_field.' '.($b && $b=='asc' ? 'asc' : 'desc');
}
} elseif ($this->stable && $this->is_field_exists($this->stable, $order_field)) {
$order_arr[] = $this->stable.'.'.$order_field.' '.($b && $b=='asc' ? 'asc' : 'desc');
}
}
if ($order_arr) {
$order_str = implode(',', $order_arr);
}
}
$query = $select->orderBy($order_str ? $order_str : 'id desc')->get();
if (!$query) {
log_message('debug', '数据查询失败:'.$this->table);
$this->_clear();
return [[], $total, $param];
}
$data = $query->getResultArray();
$param['order'] = $order;
$param['total'] = $total;
// 收尾工作
$this->_clear();
return [$data, $total, $param];
}
/**
* 是否含标识符引号字符(` " [)
*/
public function has_id_quotes($expr) {
return (bool) preg_match('/[`"\[]/', (string) $expr);
}
/**
* 是否已是列表达式(含表.字段 或已加引)
*/
public function is_column_expr($expr) {
$expr = (string) $expr;
return strpos($expr, '.') !== false || $this->has_id_quotes($expr);
}
/**
* 去掉标识符外层引号(单段)
*/
public function strip_id_quotes($id) {
return trim(preg_replace('/^[`"\[\]]+|[`"\[\]]+$/', '', (string) $id));
}
/**
* 去掉表达式中全部标识符引号,保留点号
*/
public function unquote_id($expr) {
return trim(preg_replace('/[`"\[\]]+/', '', (string) $expr));
}
/**
* 取裸字段名(剥引号后取最后一段,如 `t`.`thumb` → thumb
*/
public function bare_field($expr) {
$bare = $this->unquote_id($expr);
if ($bare === '') {
return '';
}
if (strpos($bare, '.') !== false) {
$parts = explode('.', $bare);
return (string) end($parts);
}
return $bare;
}
/**
* 单段标识符加引(走驱动 escapeIdentifiers
*/
public function quote_id($id) {
$id = $this->strip_id_quotes($id);
if ($id === '') {
return '';
}
if ($this->db && method_exists($this->db, 'escapeIdentifiers')) {
return $this->db->escapeIdentifiers($id);
}
return '`'.$id.'`';
}
/**
* 表名加引
*/
public function quote_table($table) {
return $this->quote_id($table);
}
/**
* 表.字段 加引(table、name 均可为已加引旧串,会先剥再加)
*/
public function quote_field($table, $name = '') {
if ($name === '' || $name === null) {
return $this->quote_column($table);
}
return $this->quote_id($table).'.'.$this->quote_id($name);
}
/**
* 列表达式规范化加引(支持 thumb / table.thumb / `t`.`f` / "t"."f"
*/
public function quote_column($expr) {
$bare = $this->unquote_id($expr);
if ($bare === '') {
return '';
}
if (strpos($bare, '.') !== false) {
$parts = explode('.', $bare);
$field = array_pop($parts);
$table = implode('.', $parts);
return $this->quote_field($table, $field);
}
return $this->quote_id($bare);
}
/////////////////////////////////////////////////////////////////////////
/** 字段条件:表列标识(驱动加引) */
protected function _where_field_col($table, $name) {
if ($table === '' || $table === null) {
return $this->quote_column($name);
}
// name 已是完整列表达式时只规范化
if ($this->is_column_expr($name)) {
return $this->quote_column($name);
}
return $this->quote_field($table, $name);
}
/** 多条件 OR/AND 合并(value 含 || 时用 AND */
protected function _where_field_join($value, array $where, $table) {
if (!$where) {
return $this->_where_field_col($table, 'id').' = 0';
}
$op = strpos((string) $value, '||') !== false ? ' AND ' : ' OR ';
return '('.implode($op, $where).')';
}
/**
* 尝试调用当前数据库驱动的 where 表达式方法
* @return array{0:bool,1:mixed} [是否已由驱动处理, 驱动返回值]
*/
protected function _try_db_where($method, ...$args) {
if ($this->db && method_exists($this->db, $method)) {
return [true, call_user_func_array([$this->db, $method], $args)];
}
return [false, null];
}
/**
* FIND_IN_SET 表达式(优先驱动 whereFindInSet;默认 MySQL
* @param string $column 已带标识符的列,如 `dr_x`.`uid`
*/
public function where_find_in_set($column, $value) {
list($ok, $sql) = $this->_try_db_where('whereFindInSet', (string) $column, $value);
if ($ok) {
return $sql;
}
// 默认 MySQL
if (dr_is_numeric($value)) {
return 'FIND_IN_SET('.intval($value).','.(string) $column.')';
}
return 'FIND_IN_SET("'.dr_safe_replace($value).'",'.(string) $column.')';
}
/**
* BETWEEN 条件(日期时间戳 / 数值区间统一入口;驱动可选实现 whereBetween
* @param string $column 已拼好的列名
* @param float|int $start
* @param float|int $end
*/
public function where_between($column, $start, $end) {
list($ok, $sql) = $this->_try_db_where('whereBetween', (string) $column, $start, $end);
if ($ok) {
return $sql;
}
$column = (string) $column;
if ($column === '') {
return '';
}
return $column.' BETWEEN '.$start.' AND '.$end;
}
/**
* 不等于(驱动可选 whereNe;默认 !=,避免部分库不支持 <>
* @param string $column 已拼好的列名
* @param mixed $value 比较值;空字符串表示 != ''
*/
public function where_ne($column, $value = '') {
list($ok, $sql) = $this->_try_db_where('whereNe', (string) $column, $value);
if ($ok) {
return $sql;
}
$column = (string) $column;
if ($column === '') {
return '';
}
if ($value === '' || $value === null) {
return $column." != ''";
}
if (dr_is_numeric($value)) {
return $column.' != '.$value;
}
return $column." != '".dr_safe_replace($value)."'";
}
/**
* LIKE 条件(驱动可选 whereLike
* @param string $column 已拼好的列名
* @param string $keyword 关键词(可不带 %
* @param string $side both|left|right|nonenone 表示 keyword 已含通配符)
*/
public function where_like($column, $keyword, $side = 'both') {
list($ok, $sql) = $this->_try_db_where('whereLike', (string) $column, $keyword, $side);
if ($ok) {
return $sql;
}
$column = (string) $column;
if ($column === '') {
return '';
}
$kw = trim($this->db->escapeString((string) $keyword, true), '%');
if ($side === 'right') {
$pat = $kw.'%';
} elseif ($side === 'left') {
$pat = '%'.$kw;
} elseif ($side === 'none') {
$pat = $kw;
} else {
$pat = '%'.$kw.'%';
}
return $column.' LIKE \''.$pat.'\'';
}
/**
* IN / NOT IN 表达式(驱动可选 whereInExpr;与链式 where_in 区分)
* @param string $column 已拼好的列名
* @param array|string $values 数组或逗号分隔字符串
* @param bool $not true 为 NOT IN
*/
public function where_in_expr($column, $values, $not = false) {
list($ok, $sql) = $this->_try_db_where('whereInExpr', (string) $column, $values, $not);
if ($ok) {
return $sql;
}
$column = (string) $column;
if ($column === '') {
return '';
}
if (!is_array($values)) {
$values = explode(',', (string) $values);
}
$str = '';
foreach ($values as $a) {
if (is_string($a)) {
$a = trim($a);
}
if ($a === '' || $a === null) {
continue;
}
$str .= dr_is_numeric($a) ? ','.$a : ',\''.dr_safe_replace($a).'\'';
}
$str = trim($str, ',');
if ($str === '') {
return '';
}
return $column.($not ? ' NOT IN (' : ' IN (').$str.')';
}
/**
* 大小比较(驱动可选 whereCmp)
* @param string $column 已拼好的列名
* @param string $op >|>=|<|<=
* @param mixed $value 比较值(数值不强转时原样;模板 GT 等传 intval)
*/
public function where_cmp($column, $op, $value) {
list($ok, $sql) = $this->_try_db_where('whereCmp', (string) $column, $op, $value);
if ($ok) {
return $sql;
}
$column = (string) $column;
$op = (string) $op;
if ($column === '' || !in_array($op, ['>', '>=', '<', '<='], true)) {
return '';
}
if (dr_is_numeric($value)) {
return $column.' '.$op.' '.$value;
}
return $column.' '.$op.' \''.dr_safe_replace($value).'\'';
}
// 缩略图 File/thumbvalue=1 有图;否则无图;name 可已带表前缀)
public function where_field_thumb($table, $name, $value) {
list($ok, $sql) = $this->_try_db_where('whereFieldThumb', $table, $name, $value);
if ($ok) {
return $sql;
}
$col = $this->_where_field_col($table, $name);
if ($value == 1) {
return $this->where_ne($col, '');
}
return $col." = ''";
}
// 地图范围
public function where_field_map($table, $name, $value) {
list($ok, $sql) = $this->_try_db_where('whereFieldMap', $table, $name, $value);
if ($ok) {
return $sql;
}
list($a, $km) = explode('|', $value);
list($lng, $lat) = explode(',', $a);
if ($km && $lat && $lng) {
$squares = dr_square_point($lng, $lat, $km);
$lat_col = $this->quote_field($table, $name.'_lat');
$lng_col = $this->quote_field($table, $name.'_lng');
return '('.$this->where_between($lat_col, $squares['right-bottom']['lat'], $squares['left-top']['lat'])
.' AND '.$this->where_between($lng_col, $squares['left-top']['lng'], $squares['right-bottom']['lng']).')';
}
return '1=1';
}
// DIY 字段搜索回调
public function where_field_diy($table, $name, $value, $field) {
list($ok, $sql) = $this->_try_db_where('whereFieldDiy', $table, $name, $value, $field);
if ($ok) {
return $sql;
}
return call_user_func(
'dr_diy_field_'.substr($field['setting']['option']['file'], 0, -4).'_search',
$table, $name, $value, $field
);
}
// 联动菜单
public function where_field_linkage($table, $name, $value, $field, $is_like = false) {
list($ok, $sql) = $this->_try_db_where('whereFieldLinkage', $table, $name, $value, $field, $is_like);
if ($ok) {
return $sql;
}
$arr = explode('|', $value);
$where = [];
if ($is_like && $value) {
$key = \Phpcmf\Service::L('cache')->get_file('key', 'linkage/'.SITE_ID.'_'.$field['setting']['option']['linkage'].'/');
if ($key) {
$query = $this->db->table($this->dbprefix('linkage_data_'.$key))->like('name', $value)->get();
$row = $query ? $query->getRowArray() : null;
if ($row) {
$arr[] = $row['cname'];
}
}
}
$col = $this->_where_field_col($table, $name);
foreach ($arr as $val) {
$data = dr_linkage($field['setting']['option']['linkage'], $val);
if ($data) {
if ($data['child']) {
$where[] = $col.' IN ('.$data['childids'].')';
} else {
$where[] = $col.'='.intval($data['ii']);
}
}
}
return $this->_where_field_join($value, $where, $table);
}
// 联动菜单多选
public function where_field_linkages($table, $name, $value, $field, $is_like = false) {
list($ok, $sql) = $this->_try_db_where('whereFieldLinkages', $table, $name, $value, $field, $is_like);
if ($ok) {
return $sql;
}
$arr = explode('|', $value);
$where = [];
if ($is_like && $value) {
$key = \Phpcmf\Service::L('cache')->get_file('key', 'linkage/'.SITE_ID.'_'.$field['setting']['option']['linkage'].'/');
if ($key) {
$query = $this->db->table($this->dbprefix('linkage_data_'.$key))->like('name', $value)->get();
$row = $query ? $query->getRowArray() : null;
if ($row) {
$arr[] = $row['cname'];
}
}
}
foreach ($arr as $val) {
$data = dr_linkage($field['setting']['option']['linkage'], $val);
if ($data) {
if ($data['child']) {
$ids = explode(',', $data['childids']);
foreach ($ids as $id) {
if ($id) {
$where[] = $this->where_json($table, $name, $id);
}
}
} else {
$where[] = $this->where_json($table, $name, intval($data['ii']));
}
}
}
return $this->_where_field_join($value, $where, $table);
}
// 复选 Selects / Checkbox / Cats
public function where_field_checkbox($table, $name, $value, $field, $is_like = false) {
list($ok, $sql) = $this->_try_db_where('whereFieldCheckbox', $table, $name, $value, $field, $is_like);
if ($ok) {
return $sql;
}
$arr = explode('|', $value);
$where = [];
if ($is_like && $value) {
$option = dr_format_option_array($field['setting']['option']['options']);
if ($option) {
$new = [];
foreach ($option as $k => $v) {
if (strpos($v, (string) $value) !== false) {
$new[] = $k;
}
}
if ($new) {
$arr = $new;
}
}
}
foreach ($arr as $val) {
if ($val) {
$where[] = $this->where_json($table, $name, $this->db->escapeString(dr_safe_replace($val), true));
}
}
return $this->_where_field_join($value, $where, $table);
}
// Members / RelatedFIND_IN_SET
public function where_field_members($table, $name, $value) {
list($ok, $sql) = $this->_try_db_where('whereFieldMembers', $table, $name, $value);
if ($ok) {
return $sql;
}
$arr = explode('|', $value);
$where = [];
$col = $this->_where_field_col($table, $name);
foreach ($arr as $val) {
if ($val === '' || $val === null) {
continue;
}
$where[] = $this->where_find_in_set($col, $val);
}
return $this->_where_field_join($value, $where, $table);
}
// Radio / Select
public function where_field_select($table, $name, $value, $field, $is_like = false) {
list($ok, $sql) = $this->_try_db_where('whereFieldSelect', $table, $name, $value, $field, $is_like);
if ($ok) {
return $sql;
}
$arr = explode('|', $value);
if ($is_like && $value) {
$option = dr_format_option_array($field['setting']['option']['options']);
if ($option) {
$new = [];
foreach ($option as $k => $v) {
if (strpos($v, $value) !== false) {
$new[] = $k;
}
}
if ($new) {
$arr = $new;
}
}
}
$where = [];
$col = $this->_where_field_col($table, $name);
foreach ($arr as $val) {
if (dr_is_numeric($val)) {
$where[] = $col.'='.$val;
} else {
$where[] = $col.'=\''.dr_safe_replace($val, ['\\', '/']).'\'';
}
}
return $this->_where_field_join($value, $where, $table);
}
// LIKE / 多关键词
public function where_field_like($table, $name, $value) {
list($ok, $sql) = $this->_try_db_where('whereFieldLike', $table, $name, $value);
if ($ok) {
return $sql;
}
$col = $this->_where_field_col($table, $name);
$arr = explode('%', str_replace(' ', '%', $value));
if (count($arr) == 1) {
return $this->where_like($col, $value, 'both');
}
$wh = [];
foreach ($arr as $c) {
$c && $wh[] = $this->where_like($col, $c, 'both');
}
return $wh ? ('('.implode(strpos($value, '%%') !== false ? ' AND ' : ' OR ', $wh).')') : '';
}
// 等值
public function where_field_eq($table, $name, $value) {
list($ok, $sql) = $this->_try_db_where('whereFieldEq', $table, $name, $value);
if ($ok) {
return $sql;
}
$col = $this->_where_field_col($table, $name);
if (dr_is_numeric($value)) {
return $col.'='.$value;
}
return $col.'=\''.dr_safe_replace($value, ['\\', '/']).'\'';
}
// 列表搜索:按主键 id(单值或 IN)
public function where_limit_id($table, $name, $keyword) {
list($ok, $sql) = $this->_try_db_where('whereLimitId', $table, $name, $keyword);
if ($ok) {
return $sql;
}
$ids = [];
foreach (explode(',', (string) $keyword) as $i) {
$ids[] = (int) $i;
}
$col = $this->_where_field_col($table, $name);
if (dr_count($ids) == 1) {
return $col.' = '.(int) $ids[0];
}
return $col.' IN ('.implode(',', array_map('intval', $ids)).')';
}
// 列表搜索:字段 myfunc 自定义
public function where_limit_myfunc($param, $field) {
list($ok, $sql) = $this->_try_db_where('whereLimitMyfunc', $param, $field);
if ($ok) {
return $sql;
}
$func = isset($field['myfunc']) ? $field['myfunc'] : '';
if (!$func) {
return '';
}
if (!function_exists($func)) {
CI_DEBUG && log_message('debug', '字段myfunc参数中的函数('.$func.')未定义');
return '';
}
$rt = call_user_func_array($func, [$param]);
return $rt ? (string) $rt : '';
}
// 列表搜索:Uid / uid(数字按会员 id,否则按用户名查 id)
public function where_limit_uid($table, $name, $keyword) {
list($ok, $sql) = $this->_try_db_where('whereLimitUid', $table, $name, $keyword);
if ($ok) {
return $sql;
}
$col = $this->_where_field_col($table, $name);
$uid = dr_is_numeric($keyword) ? intval($keyword) : 0;
if ($uid && $this->db->table('member')->where('id', $uid)->countAllResults()) {
return $col.' = '.$uid;
}
// 用户名模糊 → 先查 id 再 IN(避免子查询方言差异)
$query = $this->db->table('member')->select('id')->like('username', $keyword)->get();
$rows = $query ? $query->getResultArray() : [];
if (!$rows) {
return '1=0';
}
$ids = [];
foreach ($rows as $r) {
$ids[] = (int) $r['id'];
}
return $col.' IN ('.implode(',', $ids).')';
}
// 列表搜索:整数
public function where_limit_int($table, $name, $keyword) {
list($ok, $sql) = $this->_try_db_where('whereLimitInt', $table, $name, $keyword);
if ($ok) {
return $sql;
}
return $this->_where_field_col($table, $name).' = '.intval($keyword);
}
// 列表搜索:表情(原文 + unicode 转义)
public function where_limit_emoji($table, $name, $keyword) {
list($ok, $sql) = $this->_try_db_where('whereLimitEmoji', $table, $name, $keyword);
if ($ok) {
return $sql;
}
$col = $this->_where_field_col($table, $name);
$key = $this->db->escapeString($keyword, true);
$key2 = $this->db->escapeString(
str_replace('\u', '\\\\\\\\u', trim(str_replace('\\', '|', json_encode($keyword)), '"')),
true
);
return '('.$col.' LIKE \'%'.$key.'%\' OR '.$col.' LIKE \'%'.$key2.'%\')';
}
// 列表搜索:准确匹配
public function where_limit_eq($table, $name, $keyword) {
list($ok, $sql) = $this->_try_db_where('whereLimitEq', $table, $name, $keyword);
if ($ok) {
return $sql;
}
return $this->where_field_eq($table, $name, $keyword);
}
// 条件
public function field($field) {
return $this->select($field);
}
public function select($field) {
if (!$field) {
return $this;
}
$this->param['select'][] = $field;
return $this;
}
/**
* 聚合/混合 SELECT(跨库安全,escape=false 交给驱动拼好引号)
* 优先驱动 buildSelectAgg;默认 MySQL 反引号
*/
public function select_agg($select) {
$select = trim((string) $select);
if ($select === '') {
return $this;
}
list($ok, $sql) = $this->_try_db_where('buildSelectAgg', $select);
if ($ok && $sql !== null && $sql !== '') {
$this->param['select_raw'][] = $sql;
} else {
$this->param['select_raw'][] = $this->_build_select_agg_default($select);
}
return $this;
}
/**
* COUNT 字段(默认 COUNT(*) AS cnt
*/
public function select_count($field = '*', $alias = 'cnt') {
return $this->_select_func('COUNT', $field, $alias);
}
/**
* SUM 字段
*/
public function select_sum($field, $alias = 'sum') {
return $this->_select_func('SUM', $field, $alias);
}
/**
* AVG 字段
*/
public function select_avg($field, $alias = 'avg') {
return $this->_select_func('AVG', $field, $alias);
}
/**
* MAX 字段
*/
public function select_max($field, $alias = 'max') {
return $this->_select_func('MAX', $field, $alias);
}
/**
* MIN 字段
*/
public function select_min($field, $alias = 'min') {
return $this->_select_func('MIN', $field, $alias);
}
/**
* 单个聚合函数 → select_raw
*/
protected function _select_func($fn, $field, $alias = '') {
$fn = strtoupper(trim((string) $fn));
$field = trim((string) $field);
$alias = trim((string) $alias);
if ($field === '' || !in_array($fn, ['COUNT', 'SUM', 'AVG', 'MAX', 'MIN'], true)) {
return $this;
}
list($ok, $sql) = $this->_try_db_where('buildSelectFunc', $fn, $field, $alias);
if ($ok && $sql !== null && $sql !== '') {
$this->param['select_raw'][] = $sql;
} else {
$this->param['select_raw'][] = $this->_build_select_func_default($fn, $field, $alias);
}
return $this;
}
/**
* 把 select / select_raw 应用到构建器
*/
protected function _apply_builder_select($builder) {
if (!empty($this->param['select'])) {
$builder->select(implode(',', $this->param['select']));
}
if (!empty($this->param['select_raw'])) {
foreach ($this->param['select_raw'] as $raw) {
if ($raw !== '' && $raw !== null) {
$builder->select($raw, false);
}
}
}
}
/**
* 默认(MySQL)聚合 SELECT 片段
*/
protected function _build_select_agg_default($select) {
$parts = $this->_split_select_parts($select);
$out = [];
foreach ($parts as $part) {
$part = trim($part);
if ($part === '') {
continue;
}
if (preg_match('/^(COUNT|SUM|AVG|MAX|MIN)\s*\(\s*(.+?)\s*\)\s*(?:AS\s+([`"]?[\w]+[`"]?))?\s*$/i', $part, $m)) {
$out[] = $this->_build_select_func_default(strtoupper($m[1]), trim($m[2]), isset($m[3]) ? trim($m[3], '`"[]') : '');
continue;
}
if (preg_match('/^(.+?)\s+AS\s+([`"]?[\w]+[`"]?)\s*$/i', $part, $m)) {
$out[] = $this->_quote_select_ident(trim($m[1])).' AS '.$this->quote_id(trim($m[2], '`"[]'));
continue;
}
$out[] = $this->_quote_select_ident($part);
}
return implode(', ', $out);
}
/**
* 默认(MySQL)单个聚合函数
*/
protected function _build_select_func_default($fn, $field, $alias = '') {
$fn = strtoupper((string) $fn);
$inner = (trim($field) === '*') ? '*' : $this->_quote_select_ident($field);
$sql = $fn.'('.$inner.')';
$alias = trim((string) $alias, '`"[]');
if ($alias !== '') {
$sql .= ' AS '.$this->quote_id($alias);
}
return $sql;
}
/**
* 列标识加引(支持 table.field / *
*/
protected function _quote_select_ident($expr) {
$expr = trim((string) $expr);
if ($expr === '' || $expr === '*') {
return $expr === '*' ? '*' : '';
}
// 已是函数或复杂表达式:原样返回(调用方应走 select_agg 解析)
if (preg_match('/[()\s]/', $expr) && !preg_match('/^[\w.`"\[\]]+$/u', $expr)) {
return $expr;
}
return $this->quote_column($expr);
}
/**
* 按逗号拆 SELECT 列表(忽略括号内逗号)
*/
protected function _split_select_parts($select) {
$parts = [];
$buf = '';
$depth = 0;
$len = strlen($select);
$quote = null;
for ($i = 0; $i < $len; $i++) {
$ch = $select[$i];
if ($quote !== null) {
$buf .= $ch;
if ($ch === $quote) {
if (($ch === "'" || $ch === '"') && $i + 1 < $len && $select[$i + 1] === $ch) {
$buf .= $select[++$i];
continue;
}
$quote = null;
}
continue;
}
if ($ch === "'" || $ch === '"' || $ch === '`') {
$quote = $ch;
$buf .= $ch;
continue;
}
if ($ch === '(') {
$depth++;
$buf .= $ch;
continue;
}
if ($ch === ')') {
$depth = max(0, $depth - 1);
$buf .= $ch;
continue;
}
if ($ch === ',' && $depth === 0) {
$parts[] = $buf;
$buf = '';
continue;
}
$buf .= $ch;
}
if (trim($buf) !== '') {
$parts[] = $buf;
}
return $parts;
}
// 条件
public function where($name, $value = '') {
if (!$name) {
return $this;
}
if (is_array($name)) {
foreach ($name as $f => $v) {
$this->param['where'][] = !dr_is_numeric($f) ? [$f, $v] : $v;
}
} else {
$this->param['where'][] = dr_strlen($value) ? [$name, $value] : $name;
}
return $this;
}
// 条件
public function like($name, $value = '') {
if (!$name) {
return $this;
}
if (method_exists($this->db, 'whereLike')) {
$this->param['where'][] = $this->db->whereLike($name, $value);
} else {
$this->param['where'][] = $name.' LIKE "%'.$value.'%"';
}
return $this;
}
// json(优先驱动 whereJson;默认 MySQL
public function where_json($table, $name, $value) {
list($ok, $sql) = $this->_try_db_where('whereJson', $table, $name, $value);
if ($ok) {
return $sql;
}
if ($this->is_column_expr($name)) {
$name = $this->quote_column($name);
} else {
$name = $table ? $this->quote_field($table, $name) : $this->quote_id($name);
}
if (version_compare($this->db->getVersion(), '5.7.0') < 0) {
return $name.' LIKE \'%"'.$value.'"%\'';
}
return "(CASE WHEN JSON_VALID({$name}) THEN JSON_CONTAINS ({$name}->'$[*]', '\"".$value."\"', '$') ELSE null END)";
}
// in条件
public function where_in($name, $value) {
if (!$name) {
return $this;
}
if (is_array($value) && $value) {
$this->param['where_in'][] = [$name, $value];
}
return $this;
}
public function where_date($name, $value) {
if (!$name) {
return $this;
}
//$where = 'DATEDIFF(from_unixtime('.$name.'),now())='.$value;
$where = '';
if (!$value) {
// 今天
$stime = strtotime(date('Y-m-d', SYS_TIME).' 00:00:00');
$etime = strtotime(date('Y-m-d 23:59:59', $stime));
$where = $name." BETWEEN ".$stime." AND ".$etime;
}
$this->param['where'][] = $where;
return $this;
}
/**
* 指定查询数量
* @access public
* @param int $offset 起始位置
* @param int $length 查询数量
* @return $this
*/
public function limit($offset, $length = 0) {
$this->param['limit'] = $offset . ($length ? ',' . $length : '');
return $this;
}
// 排序
public function order_by($value, $value2 = null) {
$this->param['order'] = $value2 ? $value.' '.$value2 : $value;
return $this;
}
public function group_by($value) {
$this->param['group'] = $value;
return $this;
}
// 运行SQL
public function query_sql($sql, $more = 0) {
$sql = str_replace('{dbprefix}', $this->prefix, $sql);
$query = $this->db->query($sql);
if (!$query || !is_object($query)) {
$this->_clear();
return [];
}
$rt = $more ? $query->getResultArray() : $query->getRowArray();
$this->_clear();
return $rt;
}
// 批量执行(插件 Install/Uninstall.sql 等)
// 经 dr_format_create_sql → 驱动 formatCreateSql 做方言转换
public function query_all($sql, $replace = []) {
if (!$sql) {
$this->_clear();
return '';
}
$rt = $this->_query_batch($sql, $replace);
$this->_clear();
return $rt['code'] ? '' : $rt['msg'];
}
/**
* 批量执行 SQL(按分号拆分),成功返回 dr_return_data(1, …)
*
* @param string $sql
* @param array $replace [0=>搜索, 1=>替换],默认含 {dbprefix}
* @return array
*/
public function _query_batch($sql, $replace = []) {
if (!isset($replace[0]) || !is_array($replace[0])) {
$replace[0] = [];
}
if (!isset($replace[1]) || !is_array($replace[1])) {
$replace[1] = [];
}
$replace[0][] = '{dbprefix}';
$replace[1][] = $this->db->DBPrefix;
$todo = [];
$count = 0;
$sql_data = explode(';SQL_FINECMS_EOL', trim(str_replace([PHP_EOL, chr(13), chr(10)], 'SQL_FINECMS_EOL', str_replace($replace[0], $replace[1], $sql))));
if ($sql_data) {
foreach ($sql_data as $query) {
if (!$query) {
continue;
}
$ret = '';
$queries = explode('SQL_FINECMS_EOL', trim($query));
foreach ($queries as $query) {
$ret .= $query[0] == '#' || $query[0].$query[1] == '--' ? '' : $query;
}
$ret = trim($ret);
if (!$ret) {
continue;
}
if ($this->db->simpleQuery(dr_format_create_sql($ret))) {
$todo[] = $ret;
$count++;
} else {
$err = $this->db->error();
return dr_return_data(0, ($err['message'] ?? '').'<br> '.$ret);
}
}
}
return dr_return_data(1, '', [$count, $todo]);
}
// 获取当前执行后的sql语句
public function get_sql_query() {
if (!$this->db) {
return '';
} elseif (!method_exists($this->db, 'getLastQuery')) {
return '';
}
$my = $this->db->getLastQuery();
if (!$my) {
$this->_clear();
return '';
}
if ($my && !method_exists($my, 'getQuery')) {
$this->_clear();
return (string)$my;
}
$rt = str_replace(PHP_EOL, ' ', $my->getQuery());
$this->_clear();
return $rt;
}
// 关闭数据库
public function close() {
if (method_exists($this->db, 'close')) {
$this->db->close();
}
}
private function _clear() {
$this->key = $this->id;
$this->date_field = 'inputtime';
$this->field = [];
$this->param = [];
if ($this->db_temp) {
// 还原默认库
$this->db = $this->db_temp;
$this->prefix = $this->db_temp->DBPrefix;
$this->db_temp = NULL;
}
}
// 附表分表规则
public function get_table_id($id) {
return floor($id / 100000);
}
// 显示数据库错误
private function _return_error($msg) {
return IS_ADMIN || IS_DEV ? dr_return_data(0, $msg) : dr_return_data(0, dr_lang('系统错误'));
}
}