rebase from live enviornment

This commit is contained in:
Rachit Bhargava
2024-01-09 22:14:20 -05:00
parent ff0b49a046
commit 3a22fcaa4a
15968 changed files with 2344674 additions and 45234 deletions

View File

@@ -0,0 +1,138 @@
<?php
/**
* Controller for backend functionality.
*
* @package WPNPS
*/
namespace Pantheon_Sessions;
/**
* Controller for backend functionality.
*/
class Admin {
/**
* Copy of the singleton instance.
*
* @var object
*/
private static $instance;
/**
* Name of capability required to perform actions.
*
* @var string
*/
private static $capability = 'manage_options';
/**
* Gets a copy of the singleton instance.
*
* @return object
*/
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new Admin();
self::$instance->setup_actions();
}
return self::$instance;
}
/**
* Load admin actions
*/
private function setup_actions() {
add_action( 'admin_menu', [ $this, 'action_admin_menu' ] );
add_action( 'wp_ajax_pantheon_clear_session', [ $this, 'handle_clear_session' ] );
}
/**
* Register the admin menu
*/
public function action_admin_menu() {
add_management_page( __( 'Pantheon Sessions', 'wp-native-php-sessions' ), __( 'Sessions', 'wp-native-php-sessions' ), self::$capability, 'pantheon-sessions', [ $this, 'handle_page' ] );
}
/**
* Render the admin page
*/
public function handle_page() {
global $wpdb;
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
require_once __DIR__ . '/class-list-table.php';
echo '<div class="wrap">';
echo '<div>';
$query_args = [
'action' => 'pantheon_clear_session',
'nonce' => wp_create_nonce( 'pantheon_clear_session' ),
'session' => 'all',
];
if ( $wpdb->get_var( "SELECT COUNT(session_id) FROM $wpdb->pantheon_sessions" ) ) {
echo '<a class="button pantheon-clear-all-sessions" style="float:right; margin-top: 9px;" href="' . esc_url( add_query_arg( $query_args, admin_url( 'admin-ajax.php' ) ) ) . '">' . esc_html__( 'Clear All', 'wp-native-php-sessions' ) . '</a>';
}
echo '<h2>' . esc_html__( 'Pantheon Sessions', 'wp-native-php-sessions' ) . '</h2>';
if ( isset( $_GET['message'] ) && in_array( $_GET['message'], [ 'delete-all-session', 'delete-session' ], true ) ) {
if ( 'delete-all-session' === $_GET['message'] ) {
$message = __( 'Cleared all sessions.', 'wp-native-php-sessions' );
} elseif ( 'delete-session' === $_GET['message'] ) {
$message = __( 'Session cleared.', 'wp-native-php-sessions' );
}
echo '<div id="message" class="updated"><p>' . esc_html( $message ) . '</p></div>';
}
echo '</div>';
$wp_list_table = new List_Table();
$wp_list_table->prepare_items();
$wp_list_table->display();
echo '</div>';
add_action( 'admin_footer', [ $this, 'action_admin_footer' ] );
}
/**
* Handle a request to clear all sessions
*/
public function handle_clear_session() {
global $wpdb;
if ( ! current_user_can( self::$capability ) || ! wp_verify_nonce( $_GET['nonce'], 'pantheon_clear_session' ) ) {
wp_die( esc_html__( "You don't have permission to do this.", 'wp-native-php-sessions' ) );
}
if ( ! empty( $_GET['session'] ) && 'all' === $_GET['session'] ) {
$wpdb->query( "DELETE FROM $wpdb->pantheon_sessions" );
$message = 'delete-all-session';
} else {
$wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->pantheon_sessions WHERE session_id=%s", sanitize_text_field( $_GET['session'] ) ) );
$message = 'delete-session';
}
wp_safe_redirect( add_query_arg( 'message', $message, wp_get_referer() ) );
exit;
}
/**
* Stuff that needs to go in the footer
*/
public function action_admin_footer() {
?>
<script>
(function($){
$(document).ready(function(){
$('.pantheon-clear-all-sessions').on('click', function( e ){
if ( ! confirm( '<?php esc_html_e( 'Are you sure you want to clear all active sessions?', 'wp-native-php-sessions' ); ?>') ) {
e.preventDefault();
}
});
});
}(jQuery))
</script>
<?php
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* CLI interface to interact with Pantheon sessions.
*
* @package WPNPS
*/
namespace Pantheon_Sessions;
use WP_CLI;
/**
* Interact with Pantheon Sessions
*/
class CLI_Command extends \WP_CLI_Command {
/**
* List all registered sessions.
*
* [--format=<format>]
* : Accepted values: table, csv, json, count, ids. Default: table
*
* @subcommand list
*/
public function list_( $args, $assoc_args ) {
global $wpdb;
if ( ! PANTHEON_SESSIONS_ENABLED ) {
WP_CLI::error( 'Pantheon Sessions is currently disabled.' );
}
$defaults = [
'format' => 'table',
'fields' => 'session_id,user_id,datetime,ip_address,data',
];
$assoc_args = array_merge( $defaults, $assoc_args );
$sessions = [];
foreach ( new \WP_CLI\Iterators\Query( "SELECT * FROM {$wpdb->pantheon_sessions} ORDER BY datetime DESC" ) as $row ) {
$sessions[] = $row;
}
\WP_CLI\Utils\Format_Items( $assoc_args['format'], $sessions, $assoc_args['fields'] );
}
/**
* Delete one or more sessions.
*
* [<session-id>...]
* : One or more session IDs
*
* [--all]
* : Delete all sessions.
*
* @subcommand delete
*/
public function delete( $args, $assoc_args ) {
global $wpdb;
if ( ! PANTHEON_SESSIONS_ENABLED ) {
WP_CLI::error( 'Pantheon Sessions is currently disabled.' );
}
if ( isset( $assoc_args['all'] ) ) {
$args = $wpdb->get_col( "SELECT session_id FROM {$wpdb->pantheon_sessions}" );
if ( empty( $args ) ) {
WP_CLI::warning( 'No sessions to delete.' );
}
}
foreach ( $args as $session_id ) {
$session = \Pantheon_Sessions\Session::get_by_sid( $session_id );
if ( $session ) {
$session->destroy();
WP_CLI::log( sprintf( 'Session destroyed: %s', $session_id ) );
} else {
WP_CLI::warning( sprintf( "Session doesn't exist: %s", $session_id ) );
}
}
}
/**
* Set id as primary key in the Native PHP Sessions plugin table.
*
* @subcommand add-index
*/
public function add_index( $args, $assoc_args ) {
$pantheon_session = new \Pantheon_Sessions();
$resume_point = isset( $assoc_args['start_point'] ) ? $assoc_args['start_point'] : 0;
$pantheon_session->add_index( $resume_point );
}
/**
* Finalizes the creation of a primary key by deleting the old data.
*
* @subcommand primary-key-finalize
*/
public function primary_key_finalize( $args, $assoc_args ) {
$pantheon_session = new \Pantheon_Sessions();
$resume_point = isset( $assoc_args['start_point'] ) ? $assoc_args['start_point'] : 0;
$pantheon_session->primary_key_finalize( $resume_point );
}
/**
* Reverts addition of primary key.
*
* @subcommand primary-key-revert
*/
public function primary_key_revert( $args, $assoc_args ) {
$pantheon_session = new \Pantheon_Sessions();
$resume_point = isset( $assoc_args['start_point'] ) ? $assoc_args['start_point'] : 0;
$pantheon_session->primary_key_revert( $resume_point );
}
}
\WP_CLI::add_command( 'pantheon session', '\Pantheon_Sessions\CLI_Command' );

View File

@@ -0,0 +1,87 @@
<?php
/**
* List table for displaying all sessions.
*
* @package WPNPS
*/
namespace Pantheon_Sessions;
/**
* List table for displaying all sessions.
*/
class List_Table extends \WP_List_Table {
/**
* Prepare the items for the list table
*/
public function prepare_items() {
global $wpdb;
$columns = $this->get_columns();
$hidden = [];
$sortable = [];
$this->_column_headers = [ $columns, $hidden, $sortable ];
$per_page = 20;
$paged = ( isset( $_GET['paged'] ) ) ? (int) $_GET['paged'] : 1;
$offset = $per_page * ( $paged - 1 );
$this->items = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->pantheon_sessions ORDER BY datetime DESC LIMIT %d,%d", $offset, $per_page ) );
$total_items = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->pantheon_sessions" );
$this->set_pagination_args(
[
'total_items' => $total_items,
'per_page' => $per_page,
]
);
}
/**
* Message for no items found
*/
public function no_items() {
esc_html_e( 'No sessions found.', 'wp-native-php-sessions' );
}
/**
* Get the columns in the list table
*/
public function get_columns() {
return [
'session_id' => __( 'Session ID', 'wp-native-php-sessions' ),
'user_id' => __( 'User ID', 'wp-native-php-sessions' ),
'ip_address' => __( 'IP Address', 'wp-native-php-sessions' ),
'datetime' => __( 'Last Active', 'wp-native-php-sessions' ),
'data' => __( 'Data', 'wp-native-php-sessions' ),
];
}
/**
* Render a column value
*
* @param object $item Session to display.
* @param string $column_name Name of the column.
*/
public function column_default( $item, $column_name ) {
if ( 'data' === $column_name ) {
return '<code>' . esc_html( $item->data ) . '</code>';
} elseif ( 'session_id' === $column_name ) {
$query_args = [
'action' => 'pantheon_clear_session',
'nonce' => wp_create_nonce( 'pantheon_clear_session' ),
'session' => $item->session_id,
];
$actions = [
'clear' => '<a href="' . esc_url( add_query_arg( $query_args, admin_url( 'admin-ajax.php' ) ) ) . '">' . esc_html__( 'Clear', 'wp-native-php-sessions' ) . '</a>',
];
return esc_html( $item->session_id ) . $this->row_actions( $actions );
} elseif ( 'datetime' === $column_name ) {
// translators: Time ago.
return esc_html( sprintf( esc_html__( '%s ago', 'wp-native-php-sessions' ), human_time_diff( strtotime( $item->datetime ) ) ) );
} else {
return esc_html( $item->$column_name );
}
}
}

View File

@@ -0,0 +1,126 @@
<?php
/**
* Implementation of 'SessionHandlerInterface' that writes to the database.
*
* @package WPNPS
*/
namespace Pantheon_Sessions;
use Pantheon_Sessions\Session;
/**
* Implementation of 'SessionHandlerInterface' that writes to the database.
*
* @package WPNPS
*/
class Session_Handler implements \SessionHandlerInterface {
/**
* Closes the session.
*
* @param string $save_path Path to where the session is to be stored.
* @param string $session_name Name of the session.
* @return boolean
*/
#[\ReturnTypeWillChange]
public function open( $save_path, $session_name ) {
return true;
}
/**
* Writes a session to the database.
*
* @param string $session_id Session id.
* @param string $session_data Session data.
* @return boolean
*/
#[\ReturnTypeWillChange]
public function write( $session_id, $session_data ) {
$session = Session::get_by_sid( $session_id );
if ( ! $session ) {
$session = Session::create_for_sid( $session_id );
}
if ( ! $session ) {
trigger_error( 'Could not write session to the database. Please check MySQL configuration.', E_USER_WARNING );
return false;
}
$session->set_data( $session_data );
return true;
}
/**
* Reads session data from the database.
*
* @param string $session_id Session id.
* @return string
*/
#[\ReturnTypeWillChange]
public function read( $session_id ) {
// Handle the case of first time visitors and clients that don't store
// cookies (eg. web crawlers).
$insecure_session_name = substr( session_name(), 1 );
if ( empty( $session_id )
|| ( ! isset( $_COOKIE[ session_name() ] ) && ! isset( $_COOKIE[ $insecure_session_name ] ) ) ) {
return '';
}
$session = Session::get_by_sid( $session_id );
if ( $session ) {
return $session->get_data() ?: '';
} else {
return '';
}
}
/**
* Destroys the session.
*
* @param string $session_id Session id.
*/
#[\ReturnTypeWillChange]
public function destroy( $session_id ) {
$session = Session::get_by_sid( $session_id );
if ( ! $session ) {
return;
}
$session->destroy();
return true;
}
/**
* Runs the garbage collection process.
*
* @param integer $maxlifetime Maximum lifetime in seconds.
*/
#[\ReturnTypeWillChange]
public function gc( $maxlifetime ) {
global $wpdb;
$wpdb = Session::restore_wpdb_if_null( $wpdb );
// Be sure to adjust 'php_value session.gc_maxlifetime' to a large enough
// value. For example, if you want user sessions to stay in your database
// for three weeks before deleting them, you need to set gc_maxlifetime
// to '1814400'. At that value, only after a user doesn't log in after
// three weeks (1814400 seconds) will his/her session be removed.
$wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->pantheon_sessions WHERE `datetime` <= %s ", gmdate( 'Y-m-d H:i:s', time() - $maxlifetime ) ) );
return true;
}
/**
* Closes the session.
*
* @return boolean
*/
#[\ReturnTypeWillChange]
public function close() {
return true;
}
}

View File

@@ -0,0 +1,322 @@
<?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';
}
}
}