Exception: Serialization of 'Closure' is not allowed

PhpExceptionSerializationClosures

Php Problem Overview


So I am not sure exactly what I would have to show you guys, how ever if you need more code please do not hesitate to ask:

So this method will set up the initMailer for Zend with in our application:

protected function _initMailer()
{
    if ('testing' !==  APPLICATION_ENV) {
        $this->bootstrap('Config');
        $options = $this->getOptions();
        $mail = new Zend_Application_Resource_Mail($options['mail']);
    }elseif ('testing'  ===  APPLICATION_ENV) {
        //change the mail transport only if dev or test
        if (APPLICATION_ENV <> 'production') {
            
            $callback = function()
            {
                return 'ZendMail_' . microtime(true) .'.tmp';
            };
            
            $mail = new Zend_Mail_Transport_File(
                array('path' => '/tmp/mail/',
                        'callback'=>$callback
                )
            );
            
            Zend_Mail::setDefaultTransport($mail);
        }
    }
    
    
    return $mail;
}

You can see the closure that lies with in. When I run any tests that use this code I get:

Exception: Serialization of 'Closure' is not allowed 

and thus all the tests in relation to this "closure" fails. So I am here asking you guys what I should do.

For clarification on the above, all were doing is saying that any email we send out we want to store information about that email in a folder in the /tmp/mail/ directory in a file.

Php Solutions


Solution 1 - Php

Apparently anonymous functions cannot be serialized.

Example

$function = function () {
	return "ABC";
};
serialize($function); // would throw error

From your code you are using Closure:

$callback = function () // <---------------------- Issue
{
	return 'ZendMail_' . microtime(true) . '.tmp';
};

Solution 1 : Replace with a normal function

Example

function emailCallback() {
	return 'ZendMail_' . microtime(true) . '.tmp';
}
$callback = "emailCallback" ;

Solution 2 : Indirect method call by array variable

If you look at http://docs.mnkras.com/libraries_23rdparty_2_zend_2_mail_2_transport_2file_8php_source.html

   public function __construct($options = null)
   63     {
   64         if ($options instanceof Zend_Config) {
   65             $options = $options->toArray();
   66         } elseif (!is_array($options)) {
   67             $options = array();
   68         }
   69 
   70         // Making sure we have some defaults to work with
   71         if (!isset($options['path'])) {
   72             $options['path'] = sys_get_temp_dir();
   73         }
   74         if (!isset($options['callback'])) {
   75             $options['callback'] = array($this, 'defaultCallback'); <- here
   76         }
   77 
   78         $this->setOptions($options);
   79     }

You can use the same approach to send the callback

$callback = array($this,"aMethodInYourClass");

Solution 2 - Php

Direct Closure serialisation is not allowed by PHP. But you can use powefull class like PHP Super Closure : https://github.com/jeremeamia/super_closure

This class is really simple to use and is bundled into the laravel framework for the queue manager.

From the github documentation :

$helloWorld = new SerializableClosure(function ($name = 'World') use ($greeting) {
    echo "{$greeting}, {$name}!\n";
});

$serialized = serialize($helloWorld);

Solution 3 - Php

As already stated: closures, out of the box, cannot be serialized.

However, using the __sleep(), __wakeup() magic methods and reflection u CAN manually make closures serializable. For more details see extending-php-5-3-closures-with-serialization-and-reflection

This makes use of reflection and the php function eval. Do note this opens up the possibility of CODE injection, so please take notice of WHAT you are serializing.

Solution 4 - Php

You have to disable Globals

 /**
 * @backupGlobals disabled
 */

Solution 5 - Php

It is experimental, not secure it has several risks like having to use eval () which can be disabled. the best would be to write your script to serialized in a heredoc example :

$code = <<<CODE
 <?php
class \$gen_class_{$user}{
 ...
}
CODE;

you can more easily use your code by serializing it or by writing it with the extension '.class.php'. you will be able to invoke your script easily and make it persistent.

https://3v4l.org/jpHm9 UPDATE PHP 8

<?php

function closure_to_str($func)
{
    $refl = new \ReflectionFunction($func); // get reflection object
    $path = $refl->getFileName();  // absolute path of php file
    $begn = $refl->getStartLine(); // have to `-1` for array index
    $endn = $refl->getEndLine();
    $dlim = PHP_EOL;
    $list = explode($dlim, file_get_contents($path));         // lines of php-file source
    $list = array_slice($list, ($begn-1), ($endn-($begn-1))); // lines of closure definition
    $last = (count($list)-1); // last line number

    if((substr_count($list[0],'function')>1)|| (substr_count($list[0],'{')>1) || (substr_count($list[$last],'}')>1))
    { throw new \Exception("Too complex context definition in: `$path`. Check lines: $begn & $endn."); }

    $list[0] = ('function'.explode('function',$list[0])[1]);
    $list[$last] = (explode('}',$list[$last])[0].'}');


    return implode($dlim,$list);
}

$test = 10;
$dog2 = function($var=0) use ($test){ 
    $var = 10;
    echo $var . PHP_EOL;
    return $test . $var;
};

echo closure_to_str($dog2)."\n\n";

RETURN STRING

function($var=0) use ($test){ 
    $var = 10;
    echo $var . PHP_EOL;
    return $test . $var;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTheWebsView Question on Stackoverflow
Solution 1 - PhpBabaView Answer on Stackoverflow
Solution 2 - PhpIfnotView Answer on Stackoverflow
Solution 3 - PhpArjanWView Answer on Stackoverflow
Solution 4 - PhpDumindu PereraView Answer on Stackoverflow
Solution 5 - PhpDarksynxView Answer on Stackoverflow