有几件事,首先:您需要调用的方法称为PDOStatement::execute,而不是exec。 exec 方法是PDO 类as the manual clearly shows 的方法。但是,PDO::exec 不是很安全,因为它不使用预准备语句,所以最好使用PDOStatement,然后使用适当的方法。从准备好的语句中获取受影响的行数也很容易......
接下来,您将准备好的语句(PDOStatement 实例)分配给名为 $stmt 的变量,但在 未定义的变量上调用 exec:$count:
$stmt = $this->database->prepare($sql);
$count->exec(array( //<--- should be $stmt->execute(array());
':lastname'=>$lastname,
':firstname'=>$firstname,
':island'=>$island,
':region'=>$region,
':province'=>$province,
':baranggay'=>$baranggay,
':city'=>$city,
':address'=>$address,
':gender'=>$gender,
':birthdate'=>$birthdate
));
然后,要获取受影响的行数,需要调用the rowCount method:
return $stmt->rowCount();
将这些问题放在一起,并应用于您的代码,您应该将代码更改为:
$stmt->execute(array());
$count = $stmt->rowCount();
//optional:
$stmt->closeCursor();
return $count;
为了完整起见,这里是使用exec 的不安全版本:
$vals = array(
'firstname' => 'Joe',
'lastname' => 'Goodboy'
);
$count = $pdo->exec(
'INSERT INTO hackable (firstname, lastname)
VALUES ("'.$vals['firstname'].'", "'.$vals['lastname'].'")'
);//all is well
//BUT:
$vals = array(
'firstname' => 'Evil", /*',
'lastname' => '*/ (SELECT CONCAT_WS(",", id, username, password)
FROM users
WHERE isAdmin = 1
LIMIT 1
)); --'
$count = $pdo->exec(
'INSERT INTO hackable (firstname, lastname)
VALUES ("'.$vals['firstname'].'", "'.$vals['lastname'].'")'
);//OUCH!!
后面的输入导致查询:
INSERT INTO hackable (firstname, lastname)
VALUES ("Evil", /*, "*/
(SELECT CONCAT_WS(",", id, username, password)
FROM users
WHERE isAdmin = 1
)); -- ", "")
这只是表明使用用户输入执行查询只是一个坏主意......
顺便说一下,一些代码审查:
请养成始终编写访问修饰符和subscribe to the coding standards most major players subscribe to 的习惯。这意味着方法应该是 camalCased:add_form 应该是 addForm。也帮自己一个忙,添加文档块:
/**
* Inserts data provided by $bind into forms table
* @param array $bind
* @return int
* @throw PDOException (if PDO::ERRMODE is set to PDO::ERRMODE_EXCEPTION)
*/
public function addForm(array $bind)
{//PUBLIC + camelCased name
$stmt = $this->database->prepare($queryString);
$stmt->execute($bind);
return $stmt->rowCount();
}
但总的来说,这个表单有一个固定的布局,并且需要给定数量的值。在较大的项目中,您最终可能会为此定义一个数据类:
class From extends DataModel
{//where DataModel is an abstract class
protected $lastname = null;
protected $firstname = null;
//all properties hiere
public function __construct(array $data)
{//use assoc array in constructor
foreach ($data as $key => $value)
{
$setter = 'set'.ucfirst($key);
if (method_exists($this, $setter))//define setters for properties!
$this->{$setter}($value);
}
}
/**
* method to turn instance into bind array
* Optionally omit null values for WHERE clauses
* @param bool $includeNulls = true
* @return array
*/
public function toBind ($includeNulls = true)
{
$bind = array(
':firstname' => $this->firstname,
':lastname' => $this->lastname,
//do this for all properties
);
if ($includeNulls === false)
return array_filter($bind);//unset null values
return $bind;
}
}
如果你想知道为什么我敦促你使用 setter 和 getter,而不是使用魔法 __get 和 __set 调用,check out some of my answers on codereview.stackexchange。我之前已经详细解释过了