web-dev-qa-db-fra.com

PHP __PHP_Incomplete_Class Object avec mes données $ _SESSION

J'ai une configuration de site qui, lors du chargement de la page, transforme toutes les chaînes soumises par l'utilisateur en objets SafeString. Pour ceux qui ne sont pas familiers avec SafeString, cela oblige essentiellement l’utilisateur à renvoyer en écho des données épurées qui empêchent XSS et tout le reste.

Quoi qu'il en soit, il y a un problème. Mon tableau $ _SESSION est rempli avec __PHP_Incomplete_Class Object. D'après ce que j'ai lu, cela est dû au fait que la classe n'a pas été initialisée avant la session, puis qu'elle n'a pas stocké d'objets de classe.

Voici mon code:

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);

Je ne vois pas comment réécrire cela pour résoudre le problème: /

Des idées?

36
dave

Lorsque vous accédez à $_SESSION, vous ne modifiez pas simplement la copie actuelle du script des données lues à partir de la session, vous écrivez des objets SafeString dans la session active.

Mais placer des objets personnalisés dans la session est risqué et c'est ce que j'essayerais généralement d'éviter. Pour pouvoir le faire, vous devez avoir défini la classe en question avant d'appeler session_start; sinon, le gestionnaire de session de PHP ne saura pas comment désérialiser les instances de cette classe et vous obtiendrez le __PHP_Incomplete_Class Object.

Donc, évitez de faire fracasser la session. Si vous devez suivre cette approche, faites une copie des données de $_SESSION dans un tableau $mysession local. Cependant, je dois dire que je pense que l’idée d’un SafeString est dangereuse et irréalisable; Je ne pense pas que cette approche sera jamais étanche. Qu'une chaîne de texte brut soit "sûre" n'a rien à voir avec sa provenance, c'est une propriété de la façon dont vous l'encodez pour le contexte cible.

Si vous obtenez une autre chaîne de texte provenant d'une source différente, telle que la base de données ou un fichier, ou calculée dans le script lui-même, le traitement doit être identique à celui d'une chaîne fournie par l'utilisateur: elle doit être htmlspecialchars ed. De toute façon, vous allez devoir écrire cette évasion. le coffre-fort ne vous gagne rien. Si vous devez envoyer la chaîne à un autre format de destination, vous aurez besoin d'un autre échappement.

Vous ne pouvez pas encapsuler tous les problèmes de traitement de chaîne dans une boîte pratique et ne jamais y penser à nouveau; ce n'est pas comme ça que les cordes fonctionnent.

60
bobince

Je sais que cela fait des années que cette question a été posée, mais je publie ma réponse car aucune des réponses ci-dessus n'explique réellement ce qui ne va pas en réalité au PO.

PHP sérialise ses sessions en utilisant les méthodes serialize et unserialize intégrées. serialize of PHP a la possibilité de sérialiser des objets PHP (c'est-à-dire des instances de classe) et de les convertir en chaîne. Lorsque vous unserialize ces chaînes, il les reconvertit avec les mêmes valeurs. Les classes qui ont des propriétés privées et qui souhaitent encoder/décoder cela ou faire quelque chose de complexe dans leur sérialisation/désérialisation implémentent les méthodes Serializable et ajoutent serialize et unserialize à la classe.

Lorsque PHP unserialize tente de désérialiser un objet de classe, mais que le nom de la classe n'est pas déclaré/requis, au lieu de donner un avertissement ou de lancer un Exception , il le convertit en un objet de __PHP_Incomplete_Class.

Si vous ne souhaitez pas que vos objets de session soient convertis en __PHP_Incomplete_Class, vous pouvez le faire en exigeant les fichiers de classe avant d'appeler session_start , ou en enregistrant une fonction de chargement automatique.

25
Steel Brain

Il vous suffit d'inclure le safestring.class.php avant d'appeler session_start() lorsque vous souhaitez lire les objets SafeString à partir de la variable $_SESSION:

<?php

require_once __WEBROOT__ . '/includes/safestring.class.php';    
session_start();

print_r($_SESSION);

et oui, si vous utilisez un framework PHP qui (très probablement) appelle session_start() en interne, assurez-vous de require_once le fichier de classe au préalable (utilisez des hooks ou tout mécanisme fourni par le framework).

6
Lukman

La réponse de Lukman est correcte. Mais vous avez déjà mentionné cela dans votre question, donc apparemment, vous ne pouvez pas instancier la classe avant le début de la session, pour une raison quelconque.

Vous pouvez vérifier si les sessions démarrent automatiquement dans la configuration php: http://www.php.net/manual/en/session.configuration.php#ini.session.auto-start

S'ils le sont et que vous ne pouvez pas vous aider, vous voudrez peut-être vérifier si vous pouvez charger vos classes avant cela: http://php.net/manual/en/language.oop5.autoload.php

Si tout le reste échoue, vous pouvez toujours sérialiser les objets avant de les stocker dans une session et les désérialiser chaque fois que vous les récupérez: http://php.net/manual/en/function.serialize. php

Je ne vois pas dans votre code où vous stockez vos variables, mais ce serait quelque chose comme 

$mystuff = unserialize($_SESSION["mystuff"]);
$mystuff->dostuff();
$_SESSION["mystuff"] = serialize($mystuff);

Assurez-vous de charger la définition de classe avant de désérialiser vos variables

2c $, * - brochet

3
commonpike

Je viens de traiter avec quelque chose comme ça. Cela m'a pris des heures pour enfin trouver comment ma commande était foutue. 

J'ai eu un fichier appelé asynchrone. 

myFile.php

ce fichier contient les éléments suivants.

$result = include ("myOtherFile.php");
return $result;

Myotherfile.php a quelque chose comme ça

require_once "lib/myClassLibs.php";
require_once "webconfig.php";

le webconfig.php avait l'appel de session_start (). 

Lib/myClassLibs a toutes les informations de classe init. Si vous vérifiez avant l'appel à webconfig, vous pouvez voir que la classe est disponible. 

Si vous vérifiez avant l'appel de webconfig, vous verrez également que la session a déjà commencé. Si vous vérifiez avant lib/myClassLibs.php, vous verrez que la session est déjà lancée.

En vérifiant mon fichier.php avant d'inclure MyOtherFile.php, vous trouvez que la session n'a pas démarré. 

Cela représentait un code hérité qui fonctionnait depuis 8 ans sans que je le manipule. J'ai sorti l'inclus du "MyOtherFile.php". Maintenant, mes sessions se synchronisent correctement. 

3
brad tittle

J'ai résolu le problème en utilisant les fonctions json_encode et json_decode

C'est là que je voulais assigner la valeur à session.

$user_json              = json_encode($user);
$_SESSION['user']           = $user_json;

C'est là que je montre à l'utilisateur après avoir décodé le json

session_start();

$user_json= $_SESSION['user'];
$user = json_decode($user_json);

Cela résout mon problème mais je ne suis pas sûr des performances ni de la sécurité. Je ne les ai pas vérifiées.

2
Ariful Haque

J'ai résolu ce problème en incluant la fonction __autoload en haut de mon fichier php. Donc ça ressemble à ça: 

<?php 
require_once("path/to/include.inc");

//Needed for serialization/deserialization
function __autoload($class_name) {
    include "path/to/". $class_name . '.php';
}

Dans PHP 5, cette fonction n'est pas nécessaire, mais j'étais bloquée jusqu'à ce que je l'utilise. J'espère que ceci aide quelqu'un d'autre!

1
janoulle

Je sais que la question est très ancienne, mais je me suis heurté à ce problème. Après plus de recherches et d’expérimentations, j’ai trouvé une solution que je considère comme une alternative acceptable au stockage des cours dans la session. C'est peut-être un peu hackish, mais cela fonctionne pour mon projet actuel.

REMARQUE: cette solution de contournement fonctionne pour moi car je démarre une session lorsqu'un utilisateur se connecte et ne souhaite pas inclure toutes les classes possibles que l'utilisateur peut rencontrer ou ne pas rencontrer pendant la session. Inclure tous les cours ne semble pas pratique ou efficace (mais peut-être que ce n'est pas mieux ???).

Premièrement, ma classe de base contient le code suivant qui renseigne automatiquement les attributs d'objet d'un tableau donné. 

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);
    }

}

La solution de contournement: J'utilise la méthode toArray () pour convertir une instance de classe en tableau avant son entrée dans la session, puis crée une nouvelle instance de la classe lors de son extraction depuis la session. 

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

// ... do stuff ...

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

C'est aussi très pratique pour écrire des classes dans une base de données et les convertir en JSON. Ces deux éléments sont plus faciles à utiliser avec un tableau PHP.

Comme je l’ai dit plus haut, c’est peut-être ou non le moyen le plus efficace de traiter ce problème. Cela soulève également la question "devrais-je utiliser les classes PHP si je vais simplement convertir en tableaux"?

1
CheddarMonkey

Mon erreur ici est que j'ai défini le paramètre session.auto_start sur on. La session serait alors initialisée avant l’appel d’une ligne de code (y compris l’autochargeur).

0
Tim