PHP:不允许序列化闭包

3
整个情境是我在我的opencart商店中添加了Facebook登录扩展,当新用户点击“使用Facebook登录”时,输入电子邮件和密码并点击登录,然后会弹出一个确认登录对话框,其中有“取消”和“登录”两个按钮。如果用户单击登录,则会带用户到我的商店,但是当用户单击“取消”时,应该将用户带回我的商店的登录页面,但是实际上它给出了以下错误:"Fatal error: uncaught exception with a message serialization of closure is not allowed,这是由于以下代码行:"$_SESSION["HA::STORE"][$key] = serialize($value); 我正在使用包含此代码行的以下函数:
public function set( $key, $value)
    {
        $key = strtolower( $key );

        $_SESSION["HA::STORE"][$key] = serialize($value);
    }

我尝试了这个代码 var_dump(serialize($value)); 它返回了一个字符串。我该如何序列化它呢?我已经搜索过,但没有找到任何有用的解决方案。
更新:
function login()
    {
        Hybrid_Logger::info( "Enter Hybrid_Provider_Adapter::login( {$this->id} ) " );

        if( ! $this->adapter ){
            throw new Exception( "Hybrid_Provider_Adapter::login() should not directly used." );
        }

        // clear all unneeded params
        foreach( Hybrid_Auth::$config["providers"] as $idpid => $params ){
            Hybrid_Auth::storage()->delete( "hauth_session.{$idpid}.hauth_return_to"    );
            Hybrid_Auth::storage()->delete( "hauth_session.{$idpid}.hauth_endpoint"     );
            Hybrid_Auth::storage()->delete( "hauth_session.{$idpid}.id_provider_params" );
        }

        // make a fresh start
        $this->logout();

        # get hybridauth base url
        $HYBRID_AUTH_URL_BASE = Hybrid_Auth::$config["base_url"];

        # we make use of session_id() as storage hash to identify the current user
        # using session_regenerate_id() will be a problem, but ..
        $this->params["hauth_token"] = session_id();

        # set request timestamp
        $this->params["hauth_time"]  = time();

        # for default HybridAuth endpoint url hauth_login_start_url
        #   auth.start  required  the IDp ID
        #   auth.time   optional  login request timestamp
        $this->params["login_start"] = $HYBRID_AUTH_URL_BASE . ( strpos( $HYBRID_AUTH_URL_BASE, '?' ) ? '&' : '?' ) . "hauth.start={$this->id}&hauth.time={$this->params["hauth_time"]}";

        # for default HybridAuth endpoint url hauth_login_done_url
        #   auth.done   required  the IDp ID
        $this->params["login_done"]  = $HYBRID_AUTH_URL_BASE . ( strpos( $HYBRID_AUTH_URL_BASE, '?' ) ? '&' : '?' ) . "hauth.done={$this->id}";

        Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.hauth_return_to"    , $this->params["hauth_return_to"] );
        Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.hauth_endpoint"     , $this->params["login_done"] ); 
        Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.id_provider_params" , $this->params );

        // store config to be used by the end point 
        Hybrid_Auth::storage()->config( "CONFIG", Hybrid_Auth::$config );

        // move on
        Hybrid_Logger::debug( "Hybrid_Provider_Adapter::login( {$this->id} ), redirect the user to login_start URL." );

        Hybrid_Auth::redirect( $this->params["login_start"] );
    }

在 function_login 中,set() 是被以下代码调用的:
Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.hauth_return_to"    , $this->params["hauth_return_to"] );
        Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.hauth_endpoint"     , $this->params["login_done"] ); 
        Hybrid_Auth::storage()->set( "hauth_session.{$this->id}.id_provider_params" , $this->params );

1
问题在于set()的调用者没有传递正确的参数。我怀疑您忘记在函数名称后面放置()来调用该函数,因此它正在尝试将函数本身存储在会话中。 - Barmar
1
显示调用 set() 的代码。 - Barmar
@Barmar 我已经更新了问题,请看一下。 - Haroon
1
如果您将某些内容存储在 $_SESSION 中,则无需手动序列化,因为该过程已经发生在会话处理程序代码中。只需执行 $_SESSION["HA::STORE"][$key] = $value; 即可。 - Sammitch
当我使用 $_SESSION["HA::STORE"][$key] = $value; 时,它会重定向回同一页。变量 $value 包含用户单击取消按钮时的地址。 - Haroon
我已经阐述了我的问题。 - Haroon
1个回答

2
我猜你正在传递或获取一个闭包作为set()方法的$value参数。
你需要使用反射检查并忽略闭包。
public function set( $key, $value)
{
    if (is_object($value)) {
        try {
            $reflection = new ReflectionFunction($value);
            if ($reflection->isClosure()) {
                //Trigger a E_USER_NOTICE if you want to avoid silently failing
                trigger_error("You cannot pass a closure as the second parameter of set()");
                return; // Do nothing else
            }
        } catch (\ReflectionException $e) {
            // Catch the exception thrown if $value is not a closure
        }
    }
    $key = strtolower( $key );

    $_SESSION["HA::STORE"][$key] = serialize($value);
}

或者您可以捕获并忽略异常:
function set( $key, $value)
{
    $key = strtolower( $key );
    try{
        $_SESSION["HA::STORE"][$key] = serialize($value);
    } catch (\Exception $e) {
        // Catch the exception thrown and handle it however you want
    }
}

或者看一下这个序列化闭包的Github项目

1
@mehar444,您没有提供足够的上下文让我进行解释。当$value是一个闭包时,运行var_dump(serialize($value));将会抛出一个异常,具体描述请参考这里:https://dev59.com/Y2Yr5IYBdhLWcg3wXJEK - Omn
在尝试您的代码后,它给了我这个: 警告:ReflectionFunction::__construct()期望参数1为字符串,在/var/www/html/mdpocketClipboards.com/catalog/model/social_login_free/hybrid/storage.php的第63行中给出数组。 - Haroon
实际上,我正在使用Facebook API。 - Haroon
当用户在Facebook登录对话框上点击取消时,我会收到错误。 - Haroon
如果你把 !is_string() 改成 is_object(),那么你就不会再收到那个警告了。我已经编辑了答案并进行了更改。 - Omn
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接