强制访问__PHP_Incomplete_Class对象属性

2021/01/17 20:41 · php ·  · 0评论

我正在为php cms写模块。在一个函数(回调)中,我可以访问来自框架代码的对象。

该对象是类型的,__PHP_Incomplete_Class因为在会话开始之前不包括所需的头文件。如果不破解核心cms代码,我将无法包括在内。

我想知道是否可以访问对象属性(向数组的广播不起作用)。我问这个问题是因为我可以看到值,var_dump()但是使用时$object->var我总是得到null。

当您取消序列化尚未包含的类的对象时,将出现此问题。例如,如果在包含该类之前调用​​session_start。

不能直接访问PHPIncompleteClass对象,但是可以使用foreach,serialize和gettype进行访问。用PHPIncompleteClass对象调用is_object将导致错误。

因此,如果您在会话中找到“ __PHP_Incomplete_Class”对象,并且在session_load之后添加了类,则可以使用以下函数:

function fixObject (&$object)
{
  if (!is_object ($object) && gettype ($object) == 'object')
    return ($object = unserialize (serialize ($object)));
  return $object;
}

这将产生一个可用的对象:

fixObject($_SESSION['member']);

I found this hack which will let you cast an object:

function casttoclass($class, $object)
{
  return unserialize(preg_replace('/^O:\d+:"[^"]++"/', 'O:' . strlen($class) . ':"' . $class . '"', serialize($object)));
}

From http://blog.adaniels.nl/articles/a-dark-corner-of-php-class-casting/

So you can do:

$obj = casttoclass('stdClass', $incompleteObject);

and then access properties as normal.


您也可以unserialize_callback_func在.htaccess / Apache配置文件中定义一个这样,您无需破解任何PHP,但是您可以按需包含文件。

另外,这里是我的fix_object()函数版本:主要更改是代码中的步骤3:将所有属性设为public

当PHP序列化一个对象时,所有私有和受保护的属性都以两个空字节为前缀!这些空字节是实际原因,为什么无法通过访问该属性,$obj->key因为实际上它类似于$obj->{NULL*NULL}key

/**
 * Takes an __PHP_Incomplete_Class and casts it to a stdClass object.
 * All properties will be made public in this step.
 *
 * @since  1.1.0
 * @param  object $object __PHP_Incomplete_Class
 * @return object
 */
function fix_object( $object ) {
    // preg_replace_callback handler. Needed to calculate new key-length.
    $fix_key = create_function(
        '$matches',
        'return ":" . strlen( $matches[1] ) . ":\"" . $matches[1] . "\"";'
    );

    // 1. Serialize the object to a string.
    $dump = serialize( $object );

    // 2. Change class-type to 'stdClass'.
    $dump = preg_replace( '/^O:\d+:"[^"]++"/', 'O:8:"stdClass"', $dump );

    // 3. Make private and protected properties public.
    $dump = preg_replace_callback( '/:\d+:"\0.*?\0([^"]+)"/', $fix_key, $dump );

    // 4. Unserialize the modified object again.
    return unserialize( $dump );
}

var_dump 不会向您显示这些NULL字节前缀,但是您可以通过以下代码看到它们:

class Test {
    private $AAA = 1;
    protected $BBB = 2;
    public $CCC = 3;
}

$test = new Test();
echo json_encode( serialize( $test ) );

// Output:
// "O:4:\"Test\":3:{s:9:\"\u0000Test\u0000AAA\";i:1;s:6:\"\u0000*\u0000BBB\";i:2;s:3:\"CCC\";i:3;}"

$test2 = fix_object( $test );
echo json_encode( serialize( $test2 ) );

// Output:
// "O:8:\"stdClass\":3:{s:3:\"AAA\";i:1;s:3:\"BBB\";i:2;s:3:\"CCC\";i:3;}"

在那里,您会看到:

  • 私有属性的前缀是 NULL + classname + NULL
  • protected属性的前缀为 NULL + "*" + NULL

如果只需要从PHP_Incomplete_Class对象访问原始数据(如类变量),则可以使用foreach hack,也可以执行以下操作:

$result_array = (array)$_SESSION['incomplete_object_index'];
echo $result_array['desired_item'];

我已经阅读了很多有关如何解决不完整的类对象的建议,而实际上我自己需要在一个电子商务项目中解决这些问题。

我发现的一个建议是简单地使用json_decode / json_encode转换不完整的类而无需预加载任何内容。但是,如果有旧的PHP版本依赖于PECL,例如在http://php.net/manual/en/function.json-encode中进行了描述,我不想冒险使用它。 php-所以我终于成功制定了自己的解决方案。

但是,代码是一种从对象中正确获取数据的方法,因此它可能无法满足所有需求-并且,如果环境中可用,它将首先使用json-solution并故障转移到手动处理如果需要的话。

它也以递归方式工作(在我自己的情况下是必需的)以保存整个数组。

/**
 * Convert a object to a data object (used for repairing __PHP_Incomplete_Class objects)
 * @param array $d
 * @return array|mixed|object
 */
function arrayObjectToStdClass($d = array())
{
    /**
     * If json_decode and json_encode exists as function, do it the simple way.
     * http://php.net/manual/en/function.json-encode.php
     */
    if (function_exists('json_decode') && function_exists('json_encode')) {
        return json_decode(json_encode($d));
    }
    $newArray = array();
    if (is_array($d) || is_object($d)) {
        foreach ($d as $itemKey => $itemValue) {
            if (is_array($itemValue)) {
                $newArray[$itemKey] = (array)$this->arrayObjectToStdClass($itemValue);
            } elseif (is_object($itemValue)) {
                $newArray[$itemKey] = (object)(array)$this->arrayObjectToStdClass($itemValue);
            } else {
                $newArray[$itemKey] = $itemValue;
            }
        }
    }
    return $newArray;
}

在需要之后将session_start()放入要从SESSION读取的对象的类中

除以下解决方案外,以上答案均未对我真正起作用:

$ object =反序列化(serialize($ object));

$ object-> function();

希望对别人有帮助

我在这里尝试了汤姆·海格答案,但发现了两个问题。

  1. 当您拥有其他“ Incomplete_Class”对象作为顶级类的属性时,它们将保持不变 __PHP_Incomplete_Class Object
  2. 如果您拥有私有属性,它们仍将在您的stdClass对象中私有

所以我重写了函数处理:

/**
 * @see: https://stackoverflow.com/a/965704/2377961
 *
 * @param  object  $object  The object that should be casted
 * @param  String  $class   The name of the class
 * @return mixed   The new created object
 */
function casttoclass($object, $class = 'stdClass')
{
  $ser_data = serialize($object);
  # preg_match_all('/O:\d+:"([^"]++)"/', $ser_data, $matches); // find all classes

  /*
   * make private and protected properties public
   *   privates  is stored as "s:14:\0class_name\0property_name")
   *   protected is stored as "s:14:\0*\0property_name")
   */
  $ser_data = preg_replace_callback('/s:\d+:"\0([^\0]+)\0([^"]+)"/',
    function($prop_match) {
      list($old, $classname, $propname) = $prop_match;
      return 's:'.strlen($propname) . ':"' . $propname . '"';
  }, $ser_data);

  // replace object-names
  $ser_data = preg_replace('/O:\d+:"[^"]++"/', 'O:' . strlen($class) . ':"' . $class . '"', $ser_data);
  return unserialize($ser_data);
}

我也切换tha函数参数,以便您可以使用

$obj = casttoclass($incompleteObject);

而且,您将获得stdClass仅具有公共属性对象。即使您在子类中有对象,它们也将stdClass使用公共属性进行转换

本文地址:http://php.askforanswer.com/qiangzhifangwen__php_incomplete_classduixiangshuxing.html
文章标签:
版权声明:本文为原创文章,版权归 admin 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!