yiisoft / yii2

Yii 2: The Fast, Secure and Professional PHP Framework
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
14.23k stars 6.91k forks source link

PHP Deprecated: Calling session_set_save_handler() in `PHP 8.4`. #20140

Open terabytesoftw opened 5 months ago

terabytesoftw commented 5 months ago

PHP Deprecated: Calling session_set_save_handler() with more than 2 arguments is deprecated in /home/runner/work/yii2/yii2/framework/web/Session.php on line 187

@rob006 @samdark @bizley

This is the last error we have left in PHP 8.4, which would be the best way to fix it.

rob006 commented 5 months ago

https://wiki.php.net/rfc/deprecate_functions_with_overloaded_signatures#session_set_save_handler

Suggested backward compatible alternative: code which calls session_set_save_handler() with 6 or more arguments should wrap the callbacks into a SessionHandlerInterface implementation.

terabytesoftw commented 5 months ago
class SessionHandlerInterface {
    /* Métodos */
    abstract public close(): bool
    abstract public destroy(string $session_id): bool
    abstract public gc(int $maxlifetime): int
    abstract public open(string $save_path, string $session_name): bool
    abstract public read(string $session_id): string
    abstract public write(string $session_id, string $session_data): bool
}

I will have to add these new methods, and call the old ones the new methods, is it the only way to not break bc?

samdark commented 5 months ago

Seems so.

rob006 commented 5 months ago

We could create a separate decorator class to avoid adding more methods to Session.

terabytesoftw commented 1 month ago

This could be a solution to resolve this issue.

<?php

namespace yii\web;

use SessionHandlerInterface;

class SessionHandler implements SessionHandlerInterface
{
    private Session $session;

    public function __construct(Session $session)
    {
        $this->session = $session;
    }

    /**
     * @inheritDoc
     */
    public function open(string $savePath, string $sessionName): bool
    {
        return $this->session->openSession($savePath, $sessionName);
    }

    /**
     * @inheritDoc
     */
    public function close(): bool
    {
        return $this->session->closeSession();
    }

    /**
     * @inheritDoc
     */
    public function read(string $id): string
    {
        return $this->session->readSession($id);
    }

    /**
     * @inheritDoc
     */
    public function write(string $id, string $data): bool
    {
        return $this->session->writeSession($id, $data);
    }

    /**
     * @inheritDoc
     */
    public function destroy(string $id): bool
    {
        return $this->session->destroySession($id);
    }

    /**
     * @inheritDoc
     */
    public function gc(int $maxlifetime): int|false
    {
        return $this->session->gcSession($maxlifetime);
    }
}
class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Countable
    /**
     * @var SessionHandlerInterface|array|null an object implementing the SessionHandlerInterface or a configuration array.
     * If set, will be used to provide persistency instead of build-in methods.
     */
    public SessionHandlerInterface|array|null $handler = null;

        /**
     * Registers session handler.
     *
     * @throws \yii\base\InvalidConfigException
     */
    protected function registerSessionHandler()
    {
        $sessionModuleName = session_module_name();

        if (static::$_originalSessionModule === null) {
            static::$_originalSessionModule = $sessionModuleName;
        }

        if ($this->handler === null && $this->getUseCustomStorage()) {
            $this->handler = Yii::createObject(
                [
                    '__class' => SessionHandler::class,
                    '__construct()' => [$this],
                ]
            );
        }

        if ($this->handler !== null) {
            if (is_array($this->handler)) {
                $this->handler = Yii::createObject($this->handler);
            }

            if (!$this->handler instanceof SessionHandlerInterface) {
                throw new InvalidConfigException(
                    '"' . get_class($this) . '::handler" must implement the SessionHandlerInterface.'
                );
            }

            YII_DEBUG
                ? session_set_save_handler($this->handler, false) : @session_set_save_handler($this->handler, false);
        } elseif (
            $sessionModuleName !== static::$_originalSessionModule
            && static::$_originalSessionModule !== null
            && static::$_originalSessionModule !== 'user'
        ) {
            session_module_name(static::$_originalSessionModule);
        }
    }
}