Laravel Serializable Closure

repository·2.x·Indexed 20 days ago

https://github.com/laravel/serializable-closure

A PHP package for securely serializing and unserializing PHP closures. It allows closures to be stored or transmitted and reconstructed, featuring HMAC-based integrity protection via secret keys, support for unsigned closures, and customizable transformation and resolution of 'use' variables. Requires PHP 7.4+.

Tokens
2.2K
Snippets
11
Records
13
Agent score
69%

What's inside laravel-serializable-closure

  1. Caveats and limitations of Serializable Closure

    2.x

    When using this package, be aware of the following limitations:

    • REPL Environments: Serializing closures in REPL environments, such as Laravel Tinker, is not supported.
    • Source Line Ambiguity: If multiple closures are defined on the same source line and have identical signatures, they may not be distinguishable after serialization. To prevent this, ensure each closure is placed on its own line.
  2. Serialize and unserialize closures

    2.x

    To serialize a closure, wrap it in a Laravel\SerializableClosure\SerializableClosure instance and then use the standard PHP serialize() function. To restore the closure, use unserialize() and call getClosure() on the resulting object.

    Security Note: It is highly recommended to set a secret key using SerializableClosure::setSecretKey() before serialization to ensure the integrity of the serialized data.

    use Laravel\SerializableClosure\SerializableClosure;
    
    $closure = fn () => 'james';
    
    // Recommended
    SerializableClosure::setSecretKey('secret');
    
    $serialized = serialize(new SerializableClosure($closure));
    $closure = unserialize($serialized)->getClosure();
    
    echo $closure(); // james;
  3. Set a secret key for secure serialization

    2.x

    Use SerializableClosure::setSecretKey() to define a secret key. This is the recommended way to handle closures to ensure security during the serialization process.

    Laravel\SerializableClosure\SerializableClosure::setSecretKey('secret');
  4. Create an unsigned SerializableClosure

    2.x

    If you want to create a serializable instance that does not include a cryptographic signature (useful when you don't need to verify the integrity of the closure), use the unsigned() static method. This returns an UnsignedSerializableClosure instance.

    use Laravel\SerializableClosure\SerializableClosure;
    
    $closure = function () {
        return 'hello';
    };
    
    $unsigned = SerializableClosure::unsigned($closure);
  5. Use UnsignedSerializableClosure to wrap closures

    2.x

    The UnsignedSerializableClosure class provides a way to wrap a PHP Closure so that it can be serialized and later invoked. It uses a native serializer internally to handle the closure's state.

    To use it, instantiate the class with a Closure. You can then retrieve the original closure using getClosure() or execute the wrapped closure directly by invoking the instance.

    use Laravel\SerializableClosure\UnsignedSerializableClosure;
    
    $closure = function ($name) {
        return "Hello, {$name}!";
    };
    
    $serializable = new UnsignedSerializableClosure($closure);
    
    // Execute the closure
    echo $serializable("World"); // Outputs: Hello, World!
    
    // Retrieve the original closure
    $original = $serializable->getClosure();
  6. Use the Hmac signer to secure serialized closures

    2.x

    The Laravel\SerializableClosure\Signers\Hmac class implements the Signer contract to provide HMAC-based integrity protection for serialized data. It uses the sha256 algorithm to generate a hash of the serialized string using a provided secret key.

    When you call sign(), it returns an array containing the original serialized string and a base64-encoded hash. When you call verify(), it checks the provided signature array against the secret to ensure the data has not been tampered with.

    Signature Format

    The sign() method returns an associative array with the following structure:

    • serializable: The original serialized string.
    • hash: A base64-encoded HMAC hash.

    Verification

    The verify() method expects an array with the exact same keys (serializable and hash) and returns true if the hash matches the content, or false otherwise.

    use Laravel\SerializableClosure\Signers\Hmac;
    
    $signer = new Hmac('your-secret-key');
    
    // Signing data
    $signature = $signer->sign($serializedData);
    
    // Verifying data
    if ($signer->verify($signature)) {
        // Data is authentic
    }
  7. Set the secret key for signed serialization

    2.x

    Use setSecretKey($secret) to provide a secret string. When a secret is provided, the library uses an Hmac signer, and all subsequent SerializableClosure instances will use the Signed serializer. This allows you to verify that the closure has not been tampered with during serialization/deserialization.

    use Laravel\SerializableClosure\SerializableClosure;
    
    SerializableClosure::setSecretKey('your-secret-key');
  8. Configure use variable transformation and resolution

    2.x

    You can customize how use variables are handled during the serialization process using the following static methods:

    • transformUseVariablesUsing($transformer): Sets a closure that defines how variables captured by the use keyword are transformed during serialization.
    • resolveUseVariablesUsing($resolver): Sets a closure that defines how those transformed variables are resolved back to their original state during deserialization.
    use Laravel\SerializableClosure\SerializableClosure;
    
    // Example: Custom transformer
    SerializableClosure::transformUseVariablesUsing(function ($variables) {
        // logic to transform variables
        return $variables;
    });
    
    // Example: Custom resolver
    SerializableClosure::resolveUseVariablesUsing(function ($variables) {
        // logic to resolve variables
        return $variables;
    });
  9. Initialize a SerializableClosure

    2.x

    To wrap a PHP Closure so it can be serialized and deserialized, instantiate the SerializableClosure class. By default, if a secret key has been set via setSecretKey(), it will use a signed serializer to ensure integrity. Otherwise, it uses a native serializer.

    use Laravel\SerializableClosure\SerializableClosure;
    
    $closure = function ($a, $b) {
        return $a + $b;
    };
    
    $serializableClosure = new SerializableClosure($closure);