323 lines
6.3 KiB
PHP
323 lines
6.3 KiB
PHP
<?php
|
|
/**
|
|
* Individual session object.
|
|
*
|
|
* @package WPNPS
|
|
*/
|
|
|
|
namespace Pantheon_Sessions;
|
|
|
|
/**
|
|
* Individual session object.
|
|
*/
|
|
class Session {
|
|
|
|
/**
|
|
* Any sessions stored statically.
|
|
*
|
|
* @var array
|
|
*/
|
|
private static $sessions = [];
|
|
|
|
/**
|
|
* Any secure sessions stored statically.
|
|
*
|
|
* @var array
|
|
*/
|
|
private static $secure_sessions = [];
|
|
|
|
/**
|
|
* Session id.
|
|
*
|
|
* @var string
|
|
*/
|
|
private $sid;
|
|
|
|
/**
|
|
* Session data.
|
|
*
|
|
* @var array
|
|
*/
|
|
private $data;
|
|
|
|
/**
|
|
* Session user id.
|
|
*
|
|
* @var integer
|
|
*/
|
|
private $user_id;
|
|
|
|
/**
|
|
* Get a session based on its ID.
|
|
*
|
|
* @param string $sid Session id.
|
|
* @return Session|false
|
|
*/
|
|
public static function get_by_sid( $sid ) {
|
|
global $wpdb;
|
|
|
|
if ( ! $sid ) {
|
|
return false;
|
|
}
|
|
|
|
$wpdb = self::restore_wpdb_if_null( $wpdb );
|
|
|
|
$column_name = self::get_session_id_column();
|
|
$table_name = $wpdb->pantheon_sessions;
|
|
// phpcs:ignore
|
|
$session_row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table_name} WHERE {$column_name}=%s", $sid ) );
|
|
if ( ! $session_row ) {
|
|
return false;
|
|
}
|
|
|
|
return new Session( $session_row->$column_name, $session_row->data, $session_row->user_id );
|
|
}
|
|
|
|
/**
|
|
* Create a database entry for this session
|
|
*
|
|
* @param string $sid Session id.
|
|
* @return Session
|
|
*/
|
|
public static function create_for_sid( $sid ) {
|
|
global $wpdb;
|
|
|
|
$wpdb = self::restore_wpdb_if_null( $wpdb );
|
|
|
|
$insert_data = [
|
|
'session_id' => $sid,
|
|
'user_id' => (int) get_current_user_id(),
|
|
];
|
|
if ( function_exists( 'is_ssl' ) && is_ssl() ) {
|
|
$insert_data['secure_session_id'] = $sid;
|
|
}
|
|
$wpdb->insert( $wpdb->pantheon_sessions, $insert_data );
|
|
return self::get_by_sid( $sid );
|
|
}
|
|
|
|
/**
|
|
* Instantiates a session object.
|
|
*
|
|
* @param string $sid Session id.
|
|
* @param mixed $data Any session data.
|
|
* @param integer $user_id User id for the session.
|
|
*/
|
|
private function __construct( $sid, $data, $user_id ) {
|
|
$this->sid = $sid;
|
|
$this->data = $data;
|
|
$this->user_id = $user_id;
|
|
}
|
|
|
|
/**
|
|
* Get this session's ID
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_id() {
|
|
return $this->sid;
|
|
}
|
|
|
|
/**
|
|
* Get this session's data
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public function get_data() {
|
|
return maybe_unserialize( $this->data );
|
|
}
|
|
|
|
/**
|
|
* Get this session's user id.
|
|
*
|
|
* @return integer
|
|
*/
|
|
public function get_user_id() {
|
|
return (int) $this->user_id;
|
|
}
|
|
|
|
/**
|
|
* Set the user id for this session.
|
|
*
|
|
* @param integer $user_id User id.
|
|
*/
|
|
public function set_user_id( $user_id ) {
|
|
global $wpdb;
|
|
|
|
$wpdb = self::restore_wpdb_if_null( $wpdb );
|
|
|
|
$this->user_id = (int) $user_id;
|
|
$wpdb->update(
|
|
$wpdb->pantheon_sessions,
|
|
[
|
|
'user_id' => $this->user_id,
|
|
],
|
|
[ self::get_session_id_column() => $this->get_id() ]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Set the session's data
|
|
*
|
|
* @param mixed $data Session data.
|
|
*/
|
|
public function set_data( $data ) {
|
|
global $wpdb;
|
|
|
|
if ( $data === $this->get_data() ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! isset( $_SERVER['REMOTE_ADDR'] ) ) {
|
|
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
|
|
}
|
|
|
|
$wpdb = self::restore_wpdb_if_null( $wpdb );
|
|
|
|
$wpdb->update(
|
|
$wpdb->pantheon_sessions,
|
|
[
|
|
'user_id' => (int) get_current_user_id(),
|
|
'datetime' => gmdate( 'Y-m-d H:i:s' ),
|
|
'ip_address' => self::get_client_ip_server(),
|
|
'data' => maybe_serialize( $data ),
|
|
],
|
|
[ self::get_session_id_column() => $this->get_id() ]
|
|
);
|
|
|
|
$this->data = maybe_serialize( $data );
|
|
}
|
|
|
|
/**
|
|
* Get the clients ip address
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function get_client_ip_server() {
|
|
// Set default.
|
|
$ip_address = apply_filters( 'pantheon_sessions_client_ip_default', '127.0.0.1' );
|
|
$ip_source = null;
|
|
|
|
$keys = [
|
|
'HTTP_CLIENT_IP',
|
|
'HTTP_X_FORWARDED_FOR',
|
|
'HTTP_X_FORWARDED',
|
|
'HTTP_FORWARDED_FOR',
|
|
'HTTP_FORWARDED',
|
|
'REMOTE_ADDR',
|
|
];
|
|
|
|
$ip_filter_flags = apply_filters( 'pantheon_sessions_client_ip_filter_flags', FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE );
|
|
|
|
foreach ( $keys as $key ) {
|
|
if ( array_key_exists( $key, $_SERVER )
|
|
&& $_SERVER[ $key ]
|
|
) {
|
|
$_ip_address = $_SERVER[ $key ];
|
|
|
|
if ( false !== strpos( $_ip_address, ',' ) ) {
|
|
$_ip_address = trim( strstr( $_ip_address, ',', true ) );
|
|
}
|
|
|
|
if ( false === filter_var( $_ip_address, FILTER_VALIDATE_IP, $ip_filter_flags ) ) {
|
|
continue;
|
|
}
|
|
|
|
$ip_address = $_ip_address;
|
|
$ip_source = $key;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return apply_filters(
|
|
'pantheon_sessions_client_ip',
|
|
preg_replace( '/[^0-9a-fA-F:., ]/', '', $ip_address ),
|
|
$ip_source
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Destroy this session
|
|
*/
|
|
public function destroy() {
|
|
global $wpdb;
|
|
|
|
$wpdb = self::restore_wpdb_if_null( $wpdb );
|
|
|
|
$wpdb->delete( $wpdb->pantheon_sessions, [ self::get_session_id_column() => $this->get_id() ] );
|
|
|
|
// Reset $_SESSION to prevent a new session from being started.
|
|
$_SESSION = [];
|
|
|
|
$this->delete_cookies();
|
|
}
|
|
|
|
/**
|
|
* Restores $wpdb database connection if missing.
|
|
*
|
|
* @param mixed $wpdb Existing global.
|
|
* @return object
|
|
*/
|
|
public static function restore_wpdb_if_null( $wpdb ) {
|
|
if ( $wpdb instanceof \wpdb ) {
|
|
return $wpdb;
|
|
}
|
|
$dbuser = defined( 'DB_USER' ) ? DB_USER : '';
|
|
$dbpassword = defined( 'DB_PASSWORD' ) ? DB_PASSWORD : '';
|
|
$dbname = defined( 'DB_NAME' ) ? DB_NAME : '';
|
|
$dbhost = defined( 'DB_HOST' ) ? DB_HOST : '';
|
|
|
|
return new \wpdb( $dbuser, $dbpassword, $dbname, $dbhost );
|
|
}
|
|
|
|
/**
|
|
* Delete session cookies
|
|
*/
|
|
private function delete_cookies() {
|
|
|
|
// Cookies don't exist on CLI.
|
|
if ( self::is_cli() ) {
|
|
return;
|
|
}
|
|
|
|
$session_name = session_name();
|
|
$cookies = [
|
|
$session_name,
|
|
substr( $session_name, 1 ),
|
|
'S' . $session_name,
|
|
];
|
|
|
|
foreach ( $cookies as $cookie_name ) {
|
|
|
|
if ( ! isset( $_COOKIE[ $cookie_name ] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$params = session_get_cookie_params();
|
|
setcookie( $cookie_name, '', $_SERVER['REQUEST_TIME'] - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly'] );
|
|
unset( $_COOKIE[ $cookie_name ] );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Is this request via CLI?
|
|
*
|
|
* @return bool
|
|
*/
|
|
private static function is_cli() {
|
|
return 'cli' === PHP_SAPI;
|
|
}
|
|
|
|
/**
|
|
* Get the session ID column name
|
|
*
|
|
* @return string
|
|
*/
|
|
private static function get_session_id_column() {
|
|
if ( is_ssl() ) {
|
|
return 'secure_session_id';
|
|
} else {
|
|
return 'session_id';
|
|
}
|
|
}
|
|
}
|