Я экспериментирую с PHP's session_set_save_handler
и я хотел бы использовать соединение PDO, чтобы хранить данные сессии.
У меня есть эта функция как обратный вызов для действий записи:
function _write($id, $data) {
logger('_WRITE ' . $id . ' ' . $data);
try {
$access = time();
$sql = 'REPLACE INTO sessions SET id=:id, access=:access, data=:data';
logger('This is the last line in this function that appears in the log.');
$stmt = $GLOBALS['db']->prepare($sql);
logger('This never gets logged! :(');
$stmt->bindParam(':id', $id, PDO::PARAM_STR);
$stmt->bindParam(':access', $access, PDO::PARAM_INT);
$stmt->bindParam(':data', $data, PDO::PARAM_STR);
$stmt->execute();
$stmt->closeCursor();
return true;
} catch (PDOException $e) {
logger('This is never executed.');
logger($e->getTraceAsString());
}
}
Первые два сообщения журнала всегда обнаруживаются, но третье прямо после $stmt = $GLOBALS['db']->prepare($sql)
никогда не добирается до файла журнала и нет никакой трассировки исключения также.
Таблица базы данных сессий остается пустой.
Сообщение журнала от _close
обратный вызов всегда присутствует.
Вот то, как я соединяюсь с базой данных:
$db = new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
У меня есть PHP 5.2.10.
Я пытался просто работать $GLOBALS['db']->exec($sql)
с "вручную подготовленный" $sql
содержание, но это все еще перестало работать тихо. Сам запрос в порядке, я смог выполнить его через консоль дб.
После того, как VolkerK определил проблему, я нашел эту статью, которая объясняет причину позади этого странные явления. Возможно, это могло быть информативно другим также.
Наименее болезненное, волшебное решение состоит в том, что я должен был добавить ниже вызова функции к самому концу моего фронтального контроллера (основной index.php) файл:
session_write_close();
Мои ставки сделаны: $ GLOBALS ['db'] не установлен или не является экземпляром pdo (больше?) И поэтому PHP Неустранимая ошибка: происходит вызов функции-члена prepare () для объекта, не являющегося объектом
, и php отключается.
$sql = 'REPLACE INTO sessions SET id=:id, access=:access, data=:data';
logger('This is the last line in this function that appears in the log.');
if ( !isset($GLOBALS['db']) ) {
logger('there is no globals[db]');
return;
}
else if ( !is_object($GLOBALS['db']) ) {
logger('globals[db] is not an object');
return;
}
else if ( !($GLOBALS['db'] instanceof PDO) ) {
logger('globals[db] is not a PDO object');
return;
}
else {
logger('globals[db] seems ok');
}
$stmt = $GLOBALS['db']->prepare($sql);
logger('This never gets logged! :(');
Возможно, PDO не распознает синтаксис REPLACE INTO. Если базовая библиотека доступа к БД не поддерживает подготовленные операторы напрямую, PDO эмулирует их и может не иметь REPLACE INTO в своем списке возможных типов операторов.
Попробуйте проверить $ stmt-> errorCode ()
сразу после вызова подготовки?
Если это mysql, вы можете попробовать переписать подготовленный оператор следующим образом:
INSERT INTO sessions (id, access, data)
VALUES(:id, :access, :data)
ON DUPLICATE KEY UDPATE
access=VALUES(access), data=VALUES(data);
и посмотреть, получится ли вы дальше.
Мне кажется, что к типам данных ресурсов нельзя получить доступ через $ GLOBALS []
. Что-то о том, как обрабатываются ссылки, или что-то в этом роде. Если вы хотите подшутить над моей догадкой, попробуйте следующее для объявления вашей функции:
function _write($id, $data) {
global $db;
logger('_WRITE ' . $id . ' ' . $data);
try {
И вместо этого:
$stmt = $GLOBALS['db']->prepare($sql);
try
$stmt = $db->prepare($sql);
Вы также можете попробовать поймать старые добрые Exception
вместо PDOException
с; он может зацепиться за это.
Надеюсь, это поможет!