<?php
/* =================================================================================
 * License: GPL-2.0 license
 * Author: 众产®  https://ciy.cn/code
 * Version: 0.6.7
====================================================================================*/
/*
 * 用户相关函数
 * verifyfast   校验用户自动响应
 * verifyuser   校验用户登录状态，超时用户自动续期
 * nopower      访问数据库判断用户是否有权限
 * filerecord   文件记录/短链
 * savelog              log信息记录到数据库log表
 * savelogdb            增删改数据变更记录到数据库log表
 * getcatas             从字典中读取 代码数组
 * get/set config       从SaaS配置表中读写配置项
 * get/set/del memvar   从SaaS内存表中读写变量
 */

$_token = array();
$_token['type'] = 'cookie'; //cookie(更安全) 、 localstorage(兼容性好)
$_token['swapsec'] = 3600; //更换JWT时间
$_token['expsec'] = 86400 * 30; //过期退出时间
$_token['field'] = 'ciyadm';
$_token['salt'] = 'bka02$59gG'; //做数据加解密时的加密因子，每个项目都不要相同。

function verifyfast() {
    $rsuser = verifyuser();
    if ($rsuser == null)
        ciy_ouputJSON(errjson('请重新登录', 2));
    return $rsuser;
}
function verifyuser() {
    global $db;
    global $_token;
    $ciyauth = '';
    if ($_token['type'] == 'cookie')
        $ciyauth = @$_COOKIE[$_token['field']];
    if (!$ciyauth)
        $ciyauth = @$_SERVER['HTTP_CIYAUTH'];
    if (!$ciyauth)
        $ciyauth = get('_ciyauth');
    $auth = json_decode(encrypt($ciyauth, 'D', $_token['salt']), true);
    if ($auth == null)
        return null;
    $csql = new \ciy\sql('zc_online'); //弃用redis集群
    $csql->where('id', $auth['_o']);
    $onlinerow = $db->getone($csql);
    if (!is_array($onlinerow))
        return null;
    if ($onlinerow['user'] != $auth['id'])
        return null;
    if ($onlinerow['sid'] != $auth['_s'])
        return null;
    if ($onlinerow['exptimes'] < time() - $_token['expsec'])
        return null;
    if ($onlinerow['usrchg'] == 9) {
        $csql = new \ciy\sql('zc_admin');
        $csql->where('id', $auth['id']);
        $userrow = $db->getone($csql);
        if (!is_array($userrow))
            return null;
        if ($userrow['stpstatus'] != 10)
            return null;
    }
    if ($onlinerow['usrchg'] == 2) {
        header('_re: true');
    }
    if ($onlinerow['exptimes'] > time())
        return $auth;
    $exp = time() + $_token['swapsec'];
    $sid = randstr(10);
    $auth['_s'] = $sid;
    if ($db->execute('update zc_online set exptimes=?,sid=? where id=?', array($exp, $sid, $auth['_o'])) === false)
        return null;
    $authstr = json_encode($auth, JSON_PARTIAL_OUTPUT_ON_ERROR);
    $enauth = encrypt($authstr, 'E', $_token['salt']);

    if ($_token['type'] == 'cookie') {
        $headercookie = 'Set-Cookie: ' . $_token['field'] . '=' . $enauth . '; expires=' . gmdate('D, d-M-Y H:i:s T', time() + $_token['swapsec'] + $_token['expsec']) . '; path=/; httponly; SameSite=None; Secure';
        header($headercookie);
    } else {
        $_token['__ciyauth'] = $enauth;
        //header('_ciyauth: ' . $enauth);
    }
    return $auth;
}
function verifysign($pubkey, $data, $pairsign) {
    $signbin = hex2bin($pairsign);
    if ($signbin === false)
        return '签名格式错误';
    $hashbin = hex2bin(hash('sha256', $data));
    if (strpos($pubkey, '-----BEGIN RSA PUBLIC KEY-----') === false && strpos($pubkey, '-----BEGIN PUBLIC KEY-----') === false)
        $pubkey = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($pubkey, 64, "\n") . "\n-----END PUBLIC KEY-----";
    $result = openssl_verify($hashbin, $signbin, $pubkey, OPENSSL_ALGO_SHA256);
    if ($result === 0)
        return '数字证书验签失败';
    if ($result !== 1)
        return '数字证书验签错误:' . openssl_error_string();
    return true;
}
//true无权限，false有权限
function nopower($db, $userid, $chkpower) {
    $csql = new \ciy\sql('zc_admin');
    $csql->where('id', $userid);
    $csql->column('power');
    $mepower = $db->get1($csql);
    if (empty($mepower))
        return true;
    if (strlen($chkpower) < 3)
        return true;
    if ($mepower == '.*.') //超级管理员
        return false;
    $pows = explode('.', $mepower);
    foreach ($pows as $p) {
        if (empty($p))
            continue;
        if (strpos($chkpower, $p) !== 0)
            continue;
        return false;
    }
    return true;
}
function savelog($db, $userid, $types, $msg, $isrequest = false) {
    if ($isrequest) {
        $msg .= ' GET:';
        foreach ($_GET as $key => $value)
            $msg .= $key . '=' . $value . '&';
        $msg .= ' POST:';
        foreach ($_POST as $key => $value)
            $msg .= $key . '=' . $value . '&';
        $msg .= ' SERVER:';
        foreach ($_SERVER as $key => $value)
            $msg .= "\n" . $key . '=' . $value;
        $msg .= ' JSON:' . file_get_contents('php://input');
    }
    $updata = array();
    $updata['types'] = $types;
    $updata['loguser'] = $userid;
    $updata['logs'] = $msg;
    $updata['readuser'] = 0;
    $updata['addtimes'] = tostamp();
    $updata['ip'] = getip();
    $csql = new \ciy\sql('zc_log');
    $db->insert($csql, $updata);
    return false;
}
function savelogdb($db, $userid, $types, $oldrow, $newrow) {
    savelog($db, $userid, $types, logdbstr($oldrow, $newrow), false);
}
function getconfig($db, $types, $defvalue = '') {
    $csql = new \ciy\sql('zc_config');
    $csql->where('types', $types);
    $row = $db->getone($csql);
    if (is_array($row))
        return $row['params'];
    return $defvalue;
}
function setconfig($db, $types, $value) {
    $updata = array();
    $updata['types'] = $types;
    $updata['params'] = $value;
    $csql = new \ciy\sql('zc_config');
    $csql->where('types', $types);
    if ($db->update($csql, $updata) === false)
        return '操作数据库失败:' . $db->error;
    return true;
}
function getcatas($db, $cbid, $table = 'zc_cata') {
    if (is_numeric($cbid)) {
        $cbid = toint($cbid);
    } else {
        $csql = new \ciy\sql($table);
        $csql->where('codeid', $cbid);
        $csql->where('cbid=0');
        $csql->column('id');
        $cbid = toint($db->get1($csql));
        if ($cbid == 0)
            return array();
    }
    $csql = new \ciy\sql($table);
    $csql->where('cbid', $cbid)->order('csort,id');
    $csql->column('codeid as id,name,upid,name,extdata');
    $catarows = $db->get($csql);
    // $delupid = true;
    // $delextdata = false;
    // foreach ($catarows as $catarow) {
    //     if ($catarow['upid'] > 0)
    //         $delupid = true;
    //     if (!empty($catarow['extdata']))
    //         $delextdata = true;
    // }
    // if ($delupid || $delextdata) {
    //     for ($i = 0; $i < count($catarows); $i++) {
    //         if ($delupid)
    //             unset($catarows[$i]['upid']);
    //         if ($delextdata)
    //             unset($catarows[$i]['extdata']);
    //     }
    // }
    return $catarows;
}
function getmemvar($db, $types, $defvalue = '') {
    $csql = new \ciy\sql('zc_zmem_var');
    $csql->where('types', $types);
    $row = $db->getone($csql);
    if (is_array($row))
        return $row['params'];
    return $defvalue;
}
function setmemvar($db, $types, $value) {
    if (!$db)
        return false;
    $updata = array();
    $updata['types'] = $types;
    $updata['params'] = $value;
    $csql = new \ciy\sql('zc_zmem_var');
    $csql->where('types', $types);
    $row = $db->getone($csql);
    if (is_array($row)) {
        $csql = new \ciy\sql('zc_zmem_var');
        $csql->where('id', $row['id']);
        if ($db->update($csql, $updata) === false)
            return '操作数据库失败:' . $db->error;
    } else {
        if (is_array($value)) {
            $ind = strpos($value[0], '+');
            if ($ind === false) {
                $updata['params'] = 1;
            } else {
                $updata['params'] = toint(substr($value[0], $ind + 1));
            }
        }
        if ($db->insert($csql, $updata) === false)
            return '新增数据库失败:' . $db->error;
    }
    return true;
}
function delmemvar($db, $types) {
    $csql = new \ciy\sql('zc_zmem_var');
    $csql->where('types', $types);
    $db->delete($csql);
}

function addcats($cat, $val) {
    $cats = explode(',', $cat);
    $cats = array_filter($cats, function ($value) {
        return !empty($value);
    });
    if (!in_array($val, $cats))
        $cats[] = $val;
    return ',' . implode(',', $cats) . ',';
}
