我现在正在编写一些软件。读者摘要版本:用户选择一个包,输入他们的姓名、电子邮件和所需的子域。然后检查子域以查看是否有人已经注册了它,以及它是否只是字母数字。我使用OO mysqli完成了所有这些工作,但是我决定迁移到PDO。
错误的确切措辞:
SQLSTATE[42000]:语法错误或访问冲突:1064 您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本对应的手册,了解在第 1 行的"->子域"附近使用的正确语法
当我开始实例化我的 Admin 对象时,一切都很好。但是,当我调用createAccount()
函数时,所有的地狱都松动了。堆栈跟踪到处都是,我几乎不知道何时开始对此进行故障排除。我在这里检查了其他答案,它们似乎都太本地化了,所以这里是生成它的代码,然后是所有包含错误的方法。来吧。。。。
首先,产生错误的代码:
include 'classes/Admin.class.php';
$admin = new Admin('test@test.com');
try {
$admin->createAccount('John', 'Smith', 'test', 'pro');
}
catch(Exception $e) {
echo '<pre />';
echo $e->getMessage();
die(print_r($e->getTrace()));
}
管理员类构造函数
public function __construct($email) {
$this->email = $email;
include 'Database.class.php';
include 'PasswordHash.php';
define("DB_HOST", "localhost");
define("DB_USER", "root");
define("DB_PASS", "");
define("DB_NAME", "ems");
$this->data = new Database;
$this->hasher = new PasswordHash(8, false);
}
在Admin类中,检查子域
private function checkSubdomain() {
$this->data->query('SELECT * FROM clients WHERE subdomain = :subdomain');
$this->data->bind(':subdomain', $this->subdomain);
$this->data->execute();
return ($this->data->rowCount() == 0) && (ctype_alnum($this->subdomain));
}
PDO 类执行、绑定和查询
public function execute() {
return $this->stmt->execute();
}
public function query($query) {
$this->stmt = $this->dbh->prepare($query);
}
public function bind($param, $value, $type = null) {
if(is_null($type)) {
switch(true) {
case is_int($value):
$type = PDO::PARAM_INT;
break;
case is_bool($value):
$type = PDO::PARAM_BOOL;
break;
case is_null($value):
$type = PDO::PARAM_NULL;
default:
$type = PDO::PARAM_STR;
}
}
$this->stmt->bindValue($param, $value, $type);
}
这个错误在我的代码中很普遍,所以我认为它只在 PDO 类中,但我的 Session 类工作得很好。此外,我的查询仅使用 mysqli 即可完美运行,因此我对自己的语法充满信心。任何帮助将不胜感激。
根据请求,创建帐户功能:
public function createAccount($firstname, $lastname, $subdomain, $package)
{
$this->firstname = $firstname;
$this->lastname = $lastname;
$this->subdomain = $subdomain;
$this->package = $package;
//does the subdomain exist, or is it invalid?
if(!$this->checkSubdomain())
throw new Exception('This domain is not available. It can only contain letters and numbers and must not already be taken.');
//now comes the table creation, provided everything is in order
$this->setup();
}
下面是由createAccount调用的设置函数(没有所有表结构(:
private function setup() {
$isError = false;
$queries = array(
//all of these are CREATE statements, removed for security reasons
);
//need a database that matches with the client subdomain
$this->data->query('CREATE TABLE $this->subdomain');
$this->data->bind(':subdomain', $this->subdomain);
//PDO secured...execute
$this->data->execute();
$this->data->beginTransaction();
foreach($queries as $query) {
$this->data->query($query);
if(!$this->data->execute()) { //we hit some sort of error, time to GTFO of here
$isError = true;
$this->data->cancelTransaction();
//die('Error with: ' . $query);
break;
}
}
if(!$isError) {
$this->data->endTransaction();
mkdir('a/' . $this->subdomain, 0755);
$this->generatePass();
//this is where I insert the user into the admin table using PDO, removed for security
$this->data->execute();
}
$this->data->close();
}
这是导致错误的原因:
$this->data->query('CREATE TABLE $this->subdomain');
$this->data->bind(':subdomain', $this->subdomain);
正如Michael Berkowski和andrewsi在评论中指出的那样,您不能将值绑定到占位符:subdomain
因为它在查询中没有注明,即使它是PDO占位符也只能用于值而不是数据库,表或列名。
如果要动态创建此类 SQL 查询,则需要将数据库、表或列名称括在反引号引号中(以防您的列和名称包含可能会破坏查询的 SQL 保留关键字(和放置的转义值,但如果已经使用 PDO
,则不能为此使用 MySQLi
。
由于PDO没有附带real_escape_string()
可以做到这一点的方法,并且在实践中不需要转义这样的值(除非您真的有像Ye'name
这样的列,恕我直言,这完全是愚蠢的(,因此使用preg_match()
或preg_replace()
的简单过滤器就足够了:
if (preg_match('/^['w_]+$/i', $this->subdomain)) {
// note the ` (backtick), and using " (double quotes):
$this->data->query("CREATE TABLE `{$this->subdomain}`");
} else {
// throw exception or error, do not continue with creating table
}
以下是在 PHP 中使用 '
(单引号 - 撇号(对抗"
(双引号(字符串的几个示例:
$a = 1;
$b = 2;
echo '$a + $b'; // outputs: $a + $b
echo "$a + $b"; // outputs: 1 + 2
$c = array(5, 10);
echo ''$c[0] = {$c[0]}'; // outputs: '$c[0] = {$c[0]}
echo "'$c[0] = {$c[0]}"; // outputs: $c[0] = 5
双引号字符串内的{}
用于数组和对象属性访问,并且可以围绕常规变量使用。
在双引号中转义$
由'$
完成,否则它将采用变量调用。
我遇到了这个错误,但原因略有不同。 你必须在 SELECT 语句中留下空格"选择".$userfield。" 从".$usertable。' WHERE 1' 效果很好,但 'SELECT'.$userfield.'FROM'.$usertable.'WHERE 1' 惨遭失败。
$stmt = $dbh->query(
'SELECT ' . $userfield . ' FROM ' . $usertable . ' WHERE 1 '
);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
提供的信息,以防有人使用 42000 故障代码查找命中此条目。