Подтвердить что ты не робот

PHP __PHP_Incomplete_Class Объект с моими данными $_SESSION

У меня есть настройка сайта, которая при загрузке страницы превращает все отправленные пользователем строки в объекты 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);

Я не могу придумать способ переписать это, что бы решить проблему:/

Любые идеи?

4b9b3361

Ответ 1

Когда вы обращаетесь к $_SESSION, вы не просто меняете текущую script копию данных, прочитанных из сеанса, вы записываете объекты SafeString обратно в активный сеанс.

Но размещение пользовательских объектов в сеансе является изворотливым и что-то, что я обычно стараюсь избегать. Чтобы иметь возможность сделать это, вы должны определить класс, о котором идет речь, прежде чем называть session_start; если вы этого не сделаете, обработчик сеанса PHP не будет знать, как десериализовать экземпляры этого класса, и вы получите __PHP_Incomplete_Class Object.

Поэтому избегайте frobbing сеанса. Если вы должны принять этот подход, сделайте копию данных из $_SESSION в локальный массив $mysession. Тем не менее, я должен сказать, что я думаю, что вся идея SafeString опасна и неработоспособна; Я не думаю, что этот подход никогда не будет водонепроницаемым. Независимо от того, является ли строка исходного текста "безопасным", не имеет никакого отношения к тому, откуда он пришел, это свойство того, как вы кодируете его для целевого контекста.

Если вы получаете другую текстовую строку из другого источника, такого как база данных или файл, или вычисляетесь в самом script, ему нужна точно такая же обработка, как строка, которая поступает от пользователя: она должна быть htmlspecialchars изд. Вам все равно придется писать этот побег; безопасность не дает вам ничего. Если вам нужно отправить строку в другой формат назначения, вам понадобится другой выход.

Вы не можете инкапсулировать все проблемы с обработкой строк в одну удобную коробку и никогда больше не думать о них; это просто не то, как работают строки.

Ответ 2

Я знаю, что прошло много лет с тех пор, как это было задано, но я отправляю свой ответ, потому что ни один из ответов выше не объясняет OP, что на самом деле неправильно.

PHP сериализует свои сеансы, используя встроенные методы serialize и unserialize. serialize PHP имеет возможность сериализовать объекты PHP (например, экземпляры класса) и преобразовать их в строку. Когда вы unserialize эти строки, он преобразует их обратно в те же классы с этими значениями. Классы, которые имеют некоторые частные свойства и хотят кодировать/декодировать или выполнять что-то сложное в своей сериализации/десериализации, реализуют класс Serializable и добавляют serialize и unserialize.

Когда PHP unserialize пытается не инициализировать объект класса, но имя класса не объявлено/требуется, вместо того, чтобы давать предупреждение или бросать Exception, он преобразует его в объект __PHP_Incomplete_Class.

Если вы не хотите, чтобы ваши объекты сеанса конвертировались в __PHP_Incomplete_Class, вы можете сделать это, либо потребовав файлы класса, прежде чем вы вызовете session_start, или путем регистрации функции автозагрузки.

Ответ 3

Вам нужно включить 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 файл класса заранее (используйте крючки или какие-либо механизмы, которые предоставляет инфраструктура).

Ответ 4

Ответ Лукмана правильный. Но вы уже упоминаете, что в вашем вопросе, по-видимому, вы не можете создать экземпляр класса до начала сеанса по какой-то причине.

Вы можете проверить, запускаются ли сеансы автоматически в конфигурации 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);

Обязательно загрузите определение класса до того, как вы переопределите переменные

$2с, * -pike

Ответ 5

Я только что занялся чем-то вроде этого. Я провел несколько часов, чтобы наконец найти, как мой приказ был завинчен.

У меня был файл, который вызывается асинхронно.

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". Теперь мои сеансы синхронизируются должным образом.

Ответ 6

Я решил проблему, используя функции 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);

Это решает мою проблему, но я не уверен в производительности или безопасности. Я не проверял их.

Ответ 7

Я решил эту проблему, включив функцию __ 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 эта функция не нужна, но я застрял, пока не использовал эту функцию. Надеюсь, это поможет кому-то еще!

Ответ 8

Моя ошибка заключалась в том, что я установил для параметра session.auto_start значение on. Затем сессия будет инициализирована до того, как будет вызываться любая строка кода (включая автозагрузчик).

Ответ 9

Я знаю, что это действительно старый вопрос, но я столкнулся с этой проблемой. После дополнительных исследований и экспериментов я придумал, что я считаю приемлемой альтернативой хранению уроков в сессии. Это может быть немного хакерским, но работает для моего текущего проекта.

ПРИМЕЧАНИЕ: этот обходной путь работает для меня, потому что я начинаю сеанс, когда пользователь входит в систему и не хочет включать все возможные классы, которые пользователь может или не может встретить во время сеанса. Включение всех классов не кажется практичным или эффективным (но, может быть, это не лучше???).

Во-первых, мой базовый класс содержит следующий код, который автоматически заполняет атрибуты объекта из данного массива.

class BaseClass {

    public function __construct($properties=[]){
        if (!empty($properties)) {
            array_walk($properties, function ($val, $key) {
                $this->fromArray($key, $val);
            });
        }
    }

    public function fromArray($property, $value){
        return (property_exists($this, $property)) ? $this->$property = $value : null;
    }

    public function toArray(){
        return get_object_vars($this);
    }

}

Work-Around: я использую метод toArray() для преобразования экземпляра класса в массив перед его передачей в сеанс, а затем создаю новый экземпляр класса при извлечении его из сеанса.

$_SESSION['user'] = $userInstance->toArray();

// ... do stuff ...

$userInstance = new User($_SESSION['user']);

Это также очень удобно для записи классов в базу данных и преобразования в JSON. И то, и другое упрощается при работе с массивом PHP.

Как я уже говорил выше, это может или не может быть наиболее эффективным способом решения этой проблемы. Это также поднимает вопрос: "Должен ли я использовать PHP-классы, если я просто собираюсь конвертировать в массивы?"

Ответ 10

Вы можете просто позвонить,

session_start();
session_start();

дважды в вашем коде. Позвоните один раз. Проверьте необходимые классы php для повторов. Это было исправление для меня.