我可以用PHP检测和处理MySQL警告吗?
我正在处理一个MySQL表,它将JobName列定义为唯一的。如果有人试图使用数据库中已有的作业名将新作业保存到数据库中,MySQL将抛出警告 我希望能够在我的PHP脚本中检测到这个警告,就像一个错误一样,并适当地处理它。理想情况下,我想知道MySQL抛出了什么样的警告,这样我就可以对代码进行分支来处理它 这可能吗?如果没有,是因为MySQL没有这个功能,PHP没有这个功能,还是两者都没有?首先,您应该让访问者不会看到您的MySQL错误。第二,当你打电话时,你应该检查它是否返回false。如果有,打电话找出哪里出了问题。将返回的数字与上的错误代码匹配 看起来这是您要查找的错误号: 错误:1169 SQLSTATE:23000(ER_DUP_UNIQUE) 消息:由于唯一约束,无法写入表“%s”我可以用PHP检测和处理MySQL警告吗?,php,mysql,error-handling,warnings,Php,Mysql,Error Handling,Warnings,我正在处理一个MySQL表,它将JobName列定义为唯一的。如果有人试图使用数据库中已有的作业名将新作业保存到数据库中,MySQL将抛出警告 我希望能够在我的PHP脚本中检测到这个警告,就像一个错误一样,并适当地处理它。理想情况下,我想知道MySQL抛出了什么样的警告,这样我就可以对代码进行分支来处理它 这可能吗?如果没有,是因为MySQL没有这个功能,PHP没有这个功能,还是两者都没有?首先,您应该让访问者不会看到您的MySQL错误。第二,当你打电话时,你应该检查它是否返回false。如果有
更新以删除关于errno函数的内容,我现在意识到这些函数不适用于您的情况 在MySQL中,对于
UPDATE
语句需要注意的一件事是:mysqli\u infected\u rows()
将返回零,即使WHERE
子句匹配行,但SET
子句实际上并没有更改数据值。我之所以提到这一点,是因为在我曾经看过的一个系统中,这种行为导致了一个bug——程序员在更新后使用该返回值检查错误,假设零意味着发生了一些错误。这只是意味着用户在单击更新按钮之前没有更改任何现有值
因此,我想使用mysqli\u impacted\u rows()
也无法找到此类警告,除非您的表中有一个类似于update\u time
的列,在更新时该列将始终被分配一个新的时间戳值。不过,这种解决方法似乎有点困难。根据您使用的框架(如果有的话),我建议您自己进行查询以检查jobname,并创建适当的信息供用户使用,以及表单的其余验证
根据作业名称的数量,您可以将名称发送到包含表单的视图,并使用javascript告知所使用的名称
如果这对你来说没有意义,那么总结一下我的观点就是:不要设计你的程序和/或用户试图做非法的事情,在他们做的时候抓住错误,然后处理它。imho,将系统设计为不产生错误要好得多。将错误保留在实际的bug中:)对于以本机方式“标记”到PHP的警告,需要更改mysql/mysqli驱动程序,这显然超出了本问题的范围。相反,您必须基本上检查您在数据库上进行的每个查询是否存在警告:
$warningCountResult = mysql_query("SELECT @@warning_count");
if ($warningCountResult) {
$warningCount = mysql_fetch_row($warningCountResult );
if ($warningCount[0] > 0) {
//Have warnings
$warningDetailResult = mysql_query("SHOW WARNINGS");
if ($warningDetailResult ) {
while ($warning = mysql_fetch_assoc($warningDetailResult) {
//Process it
}
}
}//Else no warnings
}
显然,大规模应用这项技术的成本将非常高昂,因此您可能需要仔细考虑何时以及如何出现警告(这可能会导致您进行重构以消除警告)
作为参考
当然,您可以省去对
SELECT@@warning\u count
的初始查询,这将在每次执行时为您保存一个查询,但为了学究式的完整性,我将其包括在内。您可以使用mysqli语句错误号检测唯一的密钥冲突。mysqli语句返回错误1062,即ER\u DUP\u条目。您可以查找错误1062并打印适当的错误消息。如果您想打印列(jobName)作为错误消息的一部分,那么您应该解析语句错误字符串
if($stmt = $mysqli->prepare($sql)){
$stmt->bind_param("sss",
$name,
$identKey,
$domain);
$stmt->execute();
if($mysqli->affected_rows != 1) {
//This will return errorno 1062
trigger_error('mysql error >> '.$stmt->errno .'::' .$stmt->error, E_USER_ERROR);
exit(1);
}
$stmt->close();
} else {
trigger_error('mysql error >> '. $mysqli->errno.'::'.$mysqli->error,E_USER_ERROR);
}
如果($stmt=$mysqli->prepare($sql)){
$stmt->bind_参数(“sss”,
$name,
$identKey,
$domain);
$stmt->execute();
如果($mysqli->受影响的行!=1){
//这将返回错误号1062
触发错误('mysql错误>>'。$stmt->errno'::'。$stmt->error,E_USER_error);
出口(1);
}
$stmt->close();
}否则{
触发_错误('mysql错误>>'。$mysqli->errno'::'。$mysqli->错误,E_用户_错误);
}
使用mysqli比使用mysql更有效地获取警告是可能的 以下是php.net手册中建议的属性mysqli->warning\u count的代码:
$mysqli->query($query);
if ($mysqli->warning_count) {
if ($result = $mysqli->query("SHOW WARNINGS")) {
$row = $result->fetch_row();
printf("%s (%d): %s\n", $row[0], $row[1], $row[2]);
$result->close();
}
}
关于禁止显示警告的注意事项:一般来说,防止显示警告不是一个好主意,因为您可能遗漏了一些重要的内容。如果出于某种原因必须隐藏警告,您可以在语句前面单独放置一个
@
符号。这样,您就不必关闭所有警告报告,并且可以将其限制到特定实例
例如:
// this suppresses warnings that might result if there is no field titled "field" in the result
$field_value = @mysql_result($result, 0, "field");
可能就是你要找的
然后可以使用自定义PHP错误处理程序处理PHP错误,但您也可以关闭显示PHP错误,因为它们通常会记录到日志文件中(取决于您的PHP配置)。或者使用具有警告计数属性的MySQLi驱动程序。听起来用户希望能够捕捉到错误,而不是阻止它。最好使用
ini\u集('display\u errors',0)代码>(更好的是,把它放在php.ini中),这样用户就不会看到任何可能带来安全风险的东西。除此之外,我还建议确保将error\u log
设置为可写文件,并将error\u reporting=-1
设置为可写文件,以便了解所有潜在问题。如果我没弄错的话,他问的是警告,而不是错误。警告仍然允许查询通过,因此mysql\u query
不会返回false
。有关PHP有限的警告支持,请参见iAn的回答。
ini_set('mysql.trace_mode', 1)