我正在尝试使用REPLACE INTO来更改列的值,如果它是NULL。
以下是代码的一部分:
// Set query
$this->db->query('REPLACE INTO sessions VALUES (:id, :access, :data, :identifier)');
// Bind data
$this->db->bind(':id', $id);
$this->db->bind(':access', $access);
$this->db->bind(':data', $data);
$this->db->bind(':identifier', $rnd_id);
它是PDO的一部分,所以我一直在绑定变量以帮助防止SQL注入。
我只想在列为NULL时才替换'identifier',但我不确定SQL查询应该是什么。
修改
只是提供更多信息。上面的当前代码用于创建会话表,其中包含会话ID,上次访问会话,会话数据和唯一标识符。标识符最终将用于客户端cookie。
执行查询时,会话行会更新。 id保持不变,访问和数据更新。 我需要一种方法来更新id / access / data,但只有在它为null时才更新标识符。
以上代码基于本教程: http://culttt.com/2013/02/04/how-to-save-php-sessions-to-a-database/
我正在努力适应。
到目前为止,这是我所拥有的一切:
database.class.php
这提供了PDO连接和功能
<?php
class Database{
private $host = DB_HOST;
private $user = DB_USER;
private $pass = DB_PASSWORD;
private $dbname = DB_NAME;
private $stmt;
private $dbh;
private $error;
public function __construct(){
// Set DSN
$dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname;
// Set options
$options = array(
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
);
// Create a new PDO instanace
try{
$this->dbh = new PDO($dsn, $this->user, $this->pass, $options);
}
// Catch any errors
catch(PDOException $e){
$this->error = $e->getMessage();
}
}
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;
break;
default:
$type = PDO::PARAM_STR;
}
}
$this->stmt->bindValue($param, $value, $type);
}
public function execute(){
return $this->stmt->execute();
}
public function resultset(){
$this->execute();
return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function single(){
$this->execute();
return $this->stmt->fetch(PDO::FETCH_ASSOC);
}
public function rowCount(){
return $this->stmt->rowCount();
}
public function lastInsertId(){
return $this->dbh->lastInsertId();
}
public function beginTransaction(){
return $this->dbh->beginTransaction();
}
public function endTransaction(){
return $this->dbh->commit();
}
public function cancelTransaction(){
return $this->dbh->rollBack();
}
public function close(){
return $this->dbh=NULL;
}
}
?>
session.php文件
此代码替换PHP默认会话处理,并将数据保存到会话表,其中包含列id(会话ID),访问权限(上次访问时间)和数据(会话数据)。
include_once('database.class.php');
class Session {
/**
* Db Object
*/
private $db;
public function __construct(){
// Instantiate new Database object
$this->db = new Database;
// Set handler to overide SESSION
session_set_save_handler(
array($this, "_open"),
array($this, "_close"),
array($this, "_read"),
array($this, "_write"),
array($this, "_destroy"),
array($this, "_gc")
);
// Start the session
session_start();
}
/**
* Open
*/
public function _open(){
// If successful
if($this->db){
// Return True
return true;
}
// Return False
return false;
}
/**
* Close
*/
public function _close(){
// Close the database connection
// If successful
if($this->db->close()){
// Return True
return true;
}
// Return False
return false;
}
/**
* Read
*/
public function _read($id){
// Set query
$this->db->query('SELECT data FROM sessions WHERE id = :id');
// Bind the Id
$this->db->bind(':id', $id);
// Attempt execution
// If successful
if($this->db->execute()){
// Save returned row
$row = $this->db->single();
// Return the data
return $row['data'];
}else{
// Return an empty string
return '';
}
}
/**
* Write
*/
public function _write($id, $data){
//set the random id length
$random_id_length = 10;
//generate a random id encrypt it and store it in $rnd_id
$rnd_id = crypt(uniqid(rand(),1));
//to remove any slashes that might have come
$rnd_id = strip_tags(stripslashes($rnd_id));
//Removing any . or / and reversing the string
$rnd_id = str_replace(".","",$rnd_id);
$rnd_id = strrev(str_replace("/","",$rnd_id));
//finally I take the first 10 characters from the $rnd_id
$rnd_id = substr($rnd_id,0,$random_id_length);
// Create time stamp
$access = time();
// Set query
$this->db->query('REPLACE INTO sessions VALUES (:id, :access, :data, :identifier)');
// Bind data
$this->db->bind(':id', $id);
$this->db->bind(':access', $access);
$this->db->bind(':data', $data);
$this->db->bind(':identifier', $rnd_id);
// Attempt Execution
// If successful
if($this->db->execute()){
// Return True
return true;
}
// Return False
return false;
}
/**
* Destroy
*/
public function _destroy($id){
// Set query
$this->db->query('DELETE FROM sessions WHERE id = :id');
// Bind data
$this->db->bind(':id', $id);
// Attempt execution
// If successful
if($this->db->execute()){
// Return True
return true;
}
// Return False
return false;
}
/**
* Garbage Collection
*/
public function _gc($max){
// Calculate what is to be deemed old
$old = time() - $max;
// Set query
$this->db->query('DELETE * FROM sessions WHERE access < :old');
// Bind data
$this->db->bind(':old', $old);
// Attempt execution
if($this->db->execute()){
// Return True
return true;
}
// Return False
return false;
}
}
?>
我在表格中添加了一个新列'标识符'。我还在$rnd_id
函数中添加了_write
。这会生成10个字符的唯一标识符。
当第一次运行查询$this->db->query('REPLACE INTO sessions VALUES (:id, :access, :data, :identifier)');
时,我可以在数据库中看到一个新行,其中所有4列都按预期填充。
后续执行会出现问题 - 虽然:id保持不变,但标识符将使用新的10个字符代码进行更新。我希望防止这种情况发生,并且只在第一次添加代码。后续执行应保留标识符,或者用相同的值替换它。
答案 0 :(得分:0)
你想做这样的事吗?
UPDATE sessions
set id = :id,
access = :access,
data = :data,
identifier = :identifier
where identifier is null and id = :id;
编辑:
我认为你想要的是on duplicate key update
:
insert into sessions(id, access, data, identifier)
select :id, :access, :data, :identifier
on duplicate key update access = :access, data = :data;
您需要确保id
是主键或唯一键。你可以这样做:
create unique index idx_sessions_id on sessions(id);
答案 1 :(得分:-1)
您可以随时更新列access
和data
,如果identifier
选择了NULL
,则可以更新replace into sessions
select :id, :access, :data, coalesce(identifier, :identifier)
from sessions
where id = :id
id
尽管如果没有给定{{1}}的现有行,这会中断。如果需要插入值,当没有这样的行时,如果替换失败,则必须执行插入。
请参阅coalesce