/** @fn dbconn($fnConfirm=$GLOBALS["dbConfirmFn"]) @param fnConfirm fn(dbConnectionString), 如果返回false, 则程序中止退出。 @key dbConfirmFn 连接数据库前回调。 连接数据库 数据库由全局变量$DB(或环境变量P_DB)指定,格式可以为: host1/carsvc (无扩展名,表示某主机host1下的mysql数据库名;这时由 全局变量$DBCRED 或环境变量 P_DBCRED 指定用户名密码。 dir1/dir2/carsvc.db (以.db文件扩展名标识的文件路径,表示SQLITE数据库) 环境变量 P_DBCRED 指定用户名密码,格式为 base64(dbuser:dbpwd). */ function dbconn($fnConfirm = null) { global $DBH; if (isset($DBH)) { return $DBH; } global $DB, $DBCRED, $USE_MYSQL; // e.g. P_DB="../carsvc.db" if (!$USE_MYSQL) { $C = ["sqlite:" . $DB, '', '']; } else { // e.g. P_DB="115.29.199.210/carsvc" // e.g. P_DB="115.29.199.210:3306/carsvc" if (!preg_match('/^"?(.*?)(:(\\d+))?\\/(\\w+)"?$/', $DB, $ms)) { throw new MyException(E_SERVER, "bad db=`{$DB}`", "未知数据库"); } $dbhost = $ms[1]; $dbport = $ms[3] ?: 3306; $dbname = $ms[4]; list($dbuser, $dbpwd) = getCred($DBCRED); $C = ["mysql:host={$dbhost};dbname={$dbname};port={$dbport}", $dbuser, $dbpwd]; } if ($fnConfirm == null) { @($fnConfirm = $GLOBALS["dbConfirmFn"]); } if ($fnConfirm && $fnConfirm($C[0]) === false) { exit; } try { $DBH = new MyPDO($C[0], $C[1], $C[2]); } catch (PDOException $e) { $msg = $GLOBALS["TEST_MODE"] ? $e->getMessage() : "dbconn fails"; throw new MyException(E_DB, $msg, "数据库连接失败"); } if ($USE_MYSQL) { $DBH->exec('set names utf8'); } $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); # by default use PDO::ERRMODE_SILENT # enable real types (works on mysql after php5.4) # require driver mysqlnd (view "PDO driver" by "php -i") $DBH->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $DBH->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); return $DBH; }
function api_login() { $type = getAppType(); if ($type != "user" && $type != "emp" && $type != "admin") { throw new MyException(E_PARAM, "Unknown type `{$type}`"); } $token = param("token"); if (isset($token)) { $rv = parseLoginToken($token); $uname = $rv["uname"]; $pwd = $rv["pwd"]; } else { $uname = mparam("uname"); list($pwd, $code) = mparam(["pwd", "code"]); } $wantAll = param("wantAll/b", 0); if (isset($code) && $code != "") { validateDynCode($code, $uname); unset($pwd); } $key = "uname"; if (ctype_digit($uname[0])) { $key = "phone"; } $obj = null; # user login if ($type == "user") { $obj = "User"; $sql = sprintf("SELECT id,pwd FROM User WHERE {$key}=%s", Q($uname)); $row = queryOne($sql, PDO::FETCH_ASSOC); $ret = null; if ($row === false) { // code通过验证,直接注册新用户 if (isset($code)) { $pwd = AUTO_PWD_PREFIX . genDynCode("d4"); $ret = regUser($uname, $pwd); $ret["_isNew"] = 1; } } else { if (isset($code) || isset($pwd) && hashPwd($pwd) == $row["pwd"]) { if (!isset($pwd)) { $pwd = $row["pwd"]; } // 用于生成token $ret = ["id" => $row["id"]]; } } if (!isset($ret)) { throw new MyException(E_AUTHFAIL, "bad uname or password", "手机号或密码错误"); } $_SESSION["uid"] = $ret["id"]; } else { if ($type == "emp") { $obj = "Employee"; $sql = sprintf("SELECT id,pwd FROM Employee WHERE {$key}=%s", Q($uname)); $row = queryOne($sql, PDO::FETCH_ASSOC); if ($row === false || isset($pwd) && hashPwd($pwd) != $row["pwd"]) { throw new MyException(E_AUTHFAIL, "bad uname or password", "用户名或密码错误"); } $_SESSION["empId"] = $row["id"]; $ret = ["id" => $row["id"]]; } else { if ($type == "admin") { list($uname1, $pwd1) = getCred(getenv("P_ADMIN_CRED")); if (!isset($uname1)) { throw new MyException(E_AUTHFAIL, "admin user is not enabled.", "超级管理员用户未设置,不可登录。"); } if ($uname != $uname1 || $pwd != $pwd1) { throw new MyException(E_AUTHFAIL, "bad uname or password", "用户名或密码错误"); } $adminId = 1; $_SESSION["adminId"] = $adminId; $ret = ["id" => $adminId, "uname" => $uname1]; } } } if ($wantAll && $obj) { $rv = tableCRUD("get", $obj); $ret += $rv; } if (!isset($token)) { genLoginToken($ret, $uname, $pwd); } return $ret; }