This file is indexed.

/usr/share/php/SuperClosure/SerializableClosure.php is in php-superclosure 2.2.0-1build1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
<?php namespace SuperClosure;

use Closure;
use SuperClosure\Exception\ClosureUnserializationException;

/**
 * This class acts as a wrapper for a closure, and allows it to be serialized.
 *
 * With the combined power of the Reflection API, code parsing, and the infamous
 * `eval()` function, you can serialize a closure, unserialize it somewhere
 * else (even a different PHP process), and execute it.
 */
class SerializableClosure implements \Serializable
{
    /**
     * The closure being wrapped for serialization.
     *
     * @var Closure
     */
    private $closure;

    /**
     * The serializer doing the serialization work.
     *
     * @var SerializerInterface
     */
    private $serializer;

    /**
     * The data from unserialization.
     *
     * @var array
     */
    private $data;

    /**
     * Create a new serializable closure instance.
     *
     * @param Closure                  $closure
     * @param SerializerInterface|null $serializer
     */
    public function __construct(
        \Closure $closure,
        SerializerInterface $serializer = null
    ) {
        $this->closure = $closure;
        $this->serializer = $serializer ?: new Serializer;
    }

    /**
     * Return the original closure object.
     *
     * @return Closure
     */
    public function getClosure()
    {
        return $this->closure;
    }

    /**
     * Delegates the closure invocation to the actual closure object.
     *
     * Important Notes:
     *
     * - `ReflectionFunction::invokeArgs()` should not be used here, because it
     *   does not work with closure bindings.
     * - Args passed-by-reference lose their references when proxied through
     *   `__invoke()`. This is an unfortunate, but understandable, limitation
     *   of PHP that will probably never change.
     *
     * @return mixed
     */
    public function __invoke()
    {
        return call_user_func_array($this->closure, func_get_args());
    }

    /**
     * Clones the SerializableClosure with a new bound object and class scope.
     *
     * The method is essentially a wrapped proxy to the Closure::bindTo method.
     *
     * @param mixed $newthis  The object to which the closure should be bound,
     *                        or NULL for the closure to be unbound.
     * @param mixed $newscope The class scope to which the closure is to be
     *                        associated, or 'static' to keep the current one.
     *                        If an object is given, the type of the object will
     *                        be used instead. This determines the visibility of
     *                        protected and private methods of the bound object.
     *
     * @return SerializableClosure
     * @link http://www.php.net/manual/en/closure.bindto.php
     */
    public function bindTo($newthis, $newscope = 'static')
    {
        return new self(
            $this->closure->bindTo($newthis, $newscope),
            $this->serializer
        );
    }

    /**
     * Serializes the code, context, and binding of the closure.
     *
     * @return string|null
     * @link http://php.net/manual/en/serializable.serialize.php
     */
    public function serialize()
    {
        try {
            $this->data = $this->data ?: $this->serializer->getData($this->closure, true);
            return serialize($this->data);
        } catch (\Exception $e) {
            trigger_error(
                'Serialization of closure failed: ' . $e->getMessage(),
                E_USER_NOTICE
            );
            // Note: The serialize() method of Serializable must return a string
            // or null and cannot throw exceptions.
            return null;
        }
    }

    /**
     * Unserializes the closure.
     *
     * Unserializes the closure's data and recreates the closure using a
     * simulation of its original context. The used variables (context) are
     * extracted into a fresh scope prior to redefining the closure. The
     * closure is also rebound to its former object and scope.
     *
     * @param string $serialized
     *
     * @throws ClosureUnserializationException
     * @link http://php.net/manual/en/serializable.unserialize.php
     */
    public function unserialize($serialized)
    {
        // Unserialize the closure data and reconstruct the closure object.
        $this->data = unserialize($serialized);
        $this->closure = __reconstruct_closure($this->data);

        // Throw an exception if the closure could not be reconstructed.
        if (!$this->closure instanceof Closure) {
            throw new ClosureUnserializationException(
                'The closure is corrupted and cannot be unserialized.'
            );
        }

        // Rebind the closure to its former binding and scope.
        if ($this->data['binding'] || $this->data['isStatic']) {
            $this->closure = $this->closure->bindTo(
                $this->data['binding'],
                $this->data['scope']
            );
        }
    }

    /**
     * Returns closure data for `var_dump()`.
     *
     * @return array
     */
    public function __debugInfo()
    {
        return $this->data ?: $this->serializer->getData($this->closure, true);
    }
}

/**
 * Reconstruct a closure.
 *
 * HERE BE DRAGONS!
 *
 * The infamous `eval()` is used in this method, along with the error
 * suppression operator, and variable variables (i.e., double dollar signs) to
 * perform the unserialization logic. I'm sorry, world!
 *
 * This is also done inside a plain function instead of a method so that the
 * binding and scope of the closure are null.
 *
 * @param array $__data Unserialized closure data.
 *
 * @return Closure|null
 * @internal
 */
function __reconstruct_closure(array $__data)
{
    // Simulate the original context the closure was created in.
    foreach ($__data['context'] as $__var_name => &$__value) {
        if ($__value instanceof SerializableClosure) {
            // Unbox any SerializableClosures in the context.
            $__value = $__value->getClosure();
        } elseif ($__value === Serializer::RECURSION) {
            // Track recursive references (there should only be one).
            $__recursive_reference = $__var_name;
        }

        // Import the variable into this scope.
        ${$__var_name} = $__value;
    }

    // Evaluate the code to recreate the closure.
    try {
        if (isset($__recursive_reference)) {
            // Special handling for recursive closures.
            @eval("\${$__recursive_reference} = {$__data['code']};");
            $__closure = ${$__recursive_reference};
        } else {
            @eval("\$__closure = {$__data['code']};");
        }
    } catch (\ParseError $e) {
        // Discard the parse error.
    }

    return isset($__closure) ? $__closure : null;
}