У меня есть настройка сайта, которая при загрузке страницы превращает все отправленные пользователем строки в объекты SafeString. Для тех, кто не знаком с SafeString, он в основном заставляет пользователя эхо издать санированные данные, предотвращающие XSS и многое другое.
В любом случае, есть проблема. Мой массив $ _SESSION заполняется __PHP_Incomplete_Class Object
. Из того, что я прочитал, это связано с тем, что не инициализировало класс перед сеансом, а затем сохранил объекты класса в сеансе.
Вот мой код:
require_once __WEBROOT__ . '/includes/safestring.class.php'; $temp = array ( &$_SERVER, &$_GET, &$_POST, &$_COOKIE, &$_SESSION, &$_ENV, &$_REQUEST, &$_FILES, &$HTTP_SERVER_VARS, &$HTTP_GET_VARS, &$HTTP_POST_VARS, &$HTTP_COOKIE_VARS, &$HTTP_POST_FILES, &$HTTP_ENV_VARS ); function StringsToSafeString(&$array) { foreach ($array as $key => $value) { if (is_string($array[$key])) { $array[$key] = new SafeString($value); } if (is_array($array[$key])) { StringsToSafeString($array[$key]); } } } StringsToSafeString($temp); unset($temp);
Я не могу придумать способ переписать это, что бы решить проблему: /
Есть идеи?
Когда вы обращаетесь к $_SESSION
, вы не просто меняете копию текущего скрипта данных, прочитанных из сеанса, вы записываете объекты SafeString обратно в активный сеанс.
Но размещение пользовательских объектов в сеансе является изворотливым, и я обычно стараюсь избегать этого. Чтобы иметь возможность сделать это, вы должны определить класс, о котором идет речь, перед вызовом session_start
; если вы этого не сделаете, обработчик сеанса PHP не будет знать, как десериализировать экземпляры этого класса, и вы получите __PHP_Incomplete_Class Object
.
Поэтому избегайте frobbing сеанса. Если вы должны принять этот подход, сделайте копию данных из $_SESSION
в локальный массив $mysession
. Тем не менее, я должен сказать, что я думаю, что вся идея SafeString опасна и неработоспособна; Я не думаю, что этот подход никогда не будет водонепроницаемым. Является ли строка необработанного текста «безопасным», не имеет никакого отношения к тому, откуда он пришел, это свойство того, как вы кодируете его для целевого контекста.
Если вы получаете другую текстовую строку из другого источника, такого как база данных или файл, или вычисляетесь внутри самого скрипта, ему нужна точно такая же обработка, как и строка, которая поступает от пользователя: он должен быть htmlspecialchars
ed. Вам все равно придется писать этот побег; безопасность не дает вам ничего. Если вам нужно отправить строку в другой формат назначения, вам понадобится другой побег.
Вы не можете инкапсулировать все проблемы с обработкой строк в одну удобную коробку и никогда больше не думать о них; это просто не то, как работают струны.
Я знаю, что прошло много лет с тех пор, как меня спросили, но я отправляю свой ответ, потому что ни один из ответов выше не объясняет OP, что на самом деле неправильно.
PHP выполняет сериализацию своих сессий с использованием встроенных методов serialize
и unserialize
. serialize
PHP имеет возможность сериализовать объекты PHP (аналогично экземплярам класса) и преобразовать их в строку. Когда вы unserialize
эти строки, он преобразует их обратно теми же классами с этими значениями. Классы, которые имеют некоторые частные свойства и хотят кодировать / декодировать или выполнять что-то сложное в своей сериализации / десериализации, реализуют класс Serializable
и добавляют к классу методы serialize
и unserialize
.
Когда unserialize
PHP пытается не инициализировать объект класса, но имя класса не объявлено / не требуется, вместо того, чтобы давать предупреждение или бросать Exception
, оно преобразует его в объект __PHP_Incomplete_Class
.
Если вы не хотите, чтобы ваши объекты сеанса конвертировались в __PHP_Incomplete_Class
, вы можете сделать это, либо потребовав файлы класса перед вызовом session_start
, либо зарегистрировав функцию автозагрузки.
Вам просто нужно включить safestring.class.php
перед вызовом session_start()
когда вы хотите прочитать объекты SafeString из переменной $_SESSION
:
<?php require_once __WEBROOT__ . '/includes/safestring.class.php'; session_start(); print_r($_SESSION);
и да, если вы используете фреймворк PHP, который (по всей вероятности) вызывает session_start()
внутренне, убедитесь, что вы заранее require_once
файл класса (используйте крючки или какие-либо механизмы, которые предоставляет инфраструктура).
Я просто занимался чем-то вроде этого. Я провел несколько часов, чтобы наконец найти, как мой приказ был завинчен.
У меня был файл, который вызывается асинхронно.
myFile.php
этот файл содержал следующее.
$result = include ("myOtherFile.php"); return $result;
Myotherfile.php имеет что-то вроде этого
require_once "lib/myClassLibs.php"; require_once "webconfig.php";
у webconfig.php был вызов session_start ().
В lib / myClassLibs есть все init. Если вы проверите перед вызовом webconfig, вы увидите, что класс доступен.
Если вы проверите перед вызовом webconfig, вы также увидите, что сеанс уже запущен. Если вы проверите перед lib / myClassLibs.php, вы увидите, что сеанс уже запущен.
Проверяя в myFile.php, прежде чем вы включите MyOtherFile.php, вы обнаружите, что сеанс еще не запущен.
Это представлял собой устаревший код, который работал в течение последних 8 лет, и я не играл с ним. Я вытащил их из «MyOtherFile.php». Теперь мои сеансы синхронизируются должным образом.
Ответ Лукмана верен. Но вы уже упоминаете, что в вашем вопросе, по-видимому, вы не можете создать экземпляр класса до начала сеанса, по какой-то причине.
Вы можете проверить, запускаются ли сеансы автоматически в конфигурации php: http://www.php.net/manual/en/session.configuration.php#ini.session.auto-start
Если это так и не поможет, вы можете проверить, можете ли вы загружать свои классы до этого: http://php.net/manual/en/language.oop5.autoload.php
Если все остальное терпит неудачу, вы все равно можете сериализовать объекты до их хранения в сеансе и неаризовать их каждый из них, вы их получите: http://php.net/manual/en/function.serialize.php
Я не вижу в вашем коде, где хранятся ваши переменные, но это было бы что-то вроде
$mystuff = unserialize($_SESSION["mystuff"]); $mystuff->dostuff(); $_SESSION["mystuff"] = serialize($mystuff);
Обязательно загрузите определение класса до того, как вы переопределите переменные
$ 2c, * -pike
Я решил эту проблему, включив функцию __autoload в верхней части моего php-файла. Так выглядит:
<?php require_once("path/to/include.inc"); //Needed for serialization/deserialization function __autoload($class_name) { include "path/to/". $class_name . '.php'; }
В PHP 5 эта функция не нужна, но я застрял до тех пор, пока не использовал эту функцию. Надеюсь, это поможет кому-то еще!
Я решил проблему с помощью json_encode
и json_decode
.
Здесь я хотел присвоить значение сеансу.
$user_json = json_encode($user); $_SESSION['user'] = $user_json;
Здесь я показываю пользователю после декодирования json
session_start(); $user_json= $_SESSION['user']; $user = json_decode($user_json);
Это решает мою проблему, но я не уверен в производительности или безопасности. Я их не проверял.
Моя ошибка заключалась в том, что я установил параметр session.auto_start
для on
. Затем сессия будет инициализирована до того, как будет вызываться любая строка кода (включая автозагрузчик).
Вы можете просто позвонить,
session_start(); session_start();
дважды в вашем коде. Позвоните один раз. Проверьте необходимые классы php для повторов. Это было исправление для меня.