File: /var/www/gosurya-id/wp-content/plugins/akeebabackupwp/helpers/Solo/Session/Manager.php
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2021 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace Solo\Session;
use Awf\Session\CsrfToken;
use Awf\Session\CsrfTokenFactory;
use Awf\Session\SegmentInterface;
class Manager extends \Awf\Session\Manager
{
/**
* A session segment factory.
*
* @var SegmentFactory
*/
protected $segment_factory;
/**
* The CSRF token for this session.
*
* @var CsrfToken
*/
protected $csrf_token;
/**
* A CSRF token factory, for lazy-creating the CSRF token.
*
* @var CsrfTokenFactory
*/
protected $csrf_token_factory;
/**
* Session cookie parameters. Ignored in this implementation.
*
* @var array
*/
protected $cookie_params = [];
/**
* Session segments
*
* @var Segment[]
*/
protected $segments = [];
/**
* Session name. Used as a prefix of the user meta values.
*
* @var string
*/
private $sessionName = 'AkeebaSession';
/**
* Session ID. This is set to a random string every time we "start a session" (load stuff from the database).
*
* @var string
*/
private $sessionId = '';
public function __construct(SegmentFactory $segment_factory, CsrfTokenFactory $csrf_token_factory
)
{
$this->segment_factory = $segment_factory;
$this->csrf_token_factory = $csrf_token_factory;
}
/**
* Gets a new session segment instance by name. Segments with the same name will be different objects but will
* reference the same registry values, so it is possible to have two or more objects that share state.
*
* @param string $name The name of the session segment
*
* @return Segment
*/
public function newSegment($name)
{
if (!isset($this->segments[$name]))
{
$this->segments[$name] = $this->segment_factory->newInstance($this, $name);
}
return $this->segments[$name];
}
/**
* Tells us if a session is available to be reactivated. It won't tell you if it has started yet.
*
* @return bool
*/
public function isAvailable()
{
// CLI mode
if (!defined('WPINC'))
{
return true;
}
// Checks if the <session name>_id user meta key exists in WP's database
$metaKey = $this->getName() . '_id';
$userId = get_current_user_id();
// If the user meta key doesn't exist WP will return an empty string...
$id = get_user_meta($userId, $metaKey, true);
// ...which means we are available UNLESS $id is an empty string
return $id !== '';
}
/**
* Tells us if a session has started.
*
* @return bool
*/
public function isStarted()
{
// CLI mode
if (!defined('WPINC'))
{
return true;
}
return $this->getStatus() == PHP_SESSION_ACTIVE;
}
/**
* Starts a new session, or resumes an existing one.
*
* @return bool
*/
public function start()
{
// CLI mode
if (!defined('WPINC'))
{
return true;
}
if (!$this->isStarted())
{
// Create a random ID
$this->regenerateId();
// Save the random ID to the database
$metaKey = $this->getName() . '_id';
$userId = get_current_user_id();
update_user_meta($userId, $metaKey, $this->getId());
}
return true;
}
/**
* Clears all session variables across all segments. This is implemented by removing all WordPress user meta for
* the current user. Note that this does NOT close the session, it simply nukes its data.
*
* @return void
*/
public function clear()
{
// CLI mode
if (!defined('WPINC'))
{
return;
}
$this->clearUserMeta();
}
/**
* Writes session data from all segments and ends the session.
*
* @return void
*/
public function commit()
{
// CLI mode
if (!defined('WPINC'))
{
return;
}
if (count($this->segments))
{
/** @var SegmentInterface $segment */
foreach ($this->segments as $segment)
{
$segment->save();
}
}
// Close the session (remove the user meta with the session ID)
$userId = get_current_user_id();
delete_user_meta($userId, $this->getName() . '_id');
// Clear the ID, marking the session as closed
$this->sessionId = '';
}
/**
* Destroys the session entirely.
*
* @return bool
*/
public function destroy()
{
// CLI mode
if (!defined('WPINC'))
{
return true;
}
$this->clearUserMeta(true);
// Clear the ID, marking the session as closed
$this->sessionId = '';
return true;
}
/**
* Returns the CSRF token, creating it if needed (and thereby starting a session).
*
* @return CsrfToken
*
*/
public function getCsrfToken()
{
if (!$this->csrf_token)
{
$this->csrf_token = $this->csrf_token_factory->newInstance($this);
}
return $this->csrf_token;
}
/**
* Sets the session cache expire time. Completely ignored in this implementation.
*
* @param int $expire The expiration time in seconds.
*
* @return int
*/
public function setCacheExpire($expire)
{
return $this->getCacheExpire();
}
/**
* Gets the session cache expire time. Faked in this implementation to return PHP's default of 180 seconds.
*
* @return int The cache expiration time in seconds.
*/
public function getCacheExpire()
{
return 180;
}
/**
* Sets the session cache limiter value. Ignored in this implementation (we always emulate nocache).
*
* @param string $limiter The limiter value.
*
* @return string
*/
public function setCacheLimiter($limiter)
{
return $this->getCacheLimiter();
}
/**
* Gets the session cache limiter value.
*
* @return string The limiter value.
*/
public function getCacheLimiter()
{
return <<< END_HEADERS
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
END_HEADERS;
}
/**
* Sets the session cookie params.
*
* Cookies are completely ignored in this implementation
*
* @param array $params The array of session cookie param keys and values.
*
* @return void
*/
public function setCookieParams(array $params)
{
$this->cookie_params = array_merge($this->cookie_params, $params);
}
/**
* Gets the current session id.
*
* @return string
*/
public function getId()
{
return $this->sessionId;
}
/**
* Regenerates and replaces the current session id; also regenerates the CSRF token value if one exists.
*
* @return bool True is regeneration worked, false if not.
*
*/
public function regenerateId()
{
$this->sessionId = md5(random_bytes(32));
if ($this->csrf_token)
{
$this->csrf_token->regenerateValue();
}
return true;
}
/**
* Sets the current session name.
*
* @param string $name The session name to use.
*
* @return string
*/
public function setName($name)
{
$oldName = $this->sessionName;
$this->sessionName = $name;
return $oldName;
}
/**
* Returns the current session name.
*
* @return string
*/
public function getName()
{
return $this->sessionName;
}
/**
* Sets the session save path. Not supported by this implementation.
*
* @param string $path The new save path.
*
* @return string
*/
public function setSavePath($path)
{
return $this->getSavePath();
}
/**
* Gets the session save path. Not supported by this implementation
*
* @return string
*
*/
public function getSavePath()
{
return null;
}
/**
* Returns the current session status:
*
* - `PHP_SESSION_DISABLED` if sessions are disabled.
* - `PHP_SESSION_NONE` if sessions are enabled, but none exists.
* - `PHP_SESSION_ACTIVE` if sessions are enabled, and one exists.
*
* @return int
*
*/
public function getStatus()
{
// CLI mode
if (!defined('WPINC'))
{
return PHP_SESSION_ACTIVE;
}
$sid = $this->getId();
if (empty($sid))
{
return PHP_SESSION_NONE;
}
return PHP_SESSION_ACTIVE;
}
/**
* Clear the user meta which hold the session data
*
* @param $clearId bool Should I also clear the session ID (close the session)?
*
* @return void
*/
private function clearUserMeta($clearId = false)
{
$this->segments = [];
$userId = get_current_user_id();
$allMeta = get_user_meta($userId);
$sessionName = $this->getName();
$idKey = $sessionName . '_id';
foreach ($allMeta as $key => $value)
{
if (($key == $idKey) && !$clearId)
{
continue;
}
if (strpos($key, $sessionName . '_') === 0)
{
delete_user_meta($userId, $key);
}
}
}
}