File "WPDA_Table.php"
Full Path: /home/vantageo/public_html/cache/cache/cache/cache/cache/.wp-cli/wp-content/plugins/wp-data-access/WPDataAccess/API/WPDA_Table.php
File size: 49.47 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace WPDataAccess\API;
use stdClass;
use WPDataAccess\Connection\WPDADB;
use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Access;
use WPDataAccess\Data_Dictionary\WPDA_List_Columns_Cache;
use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model;
use WPDataAccess\Utilities\WPDA_WP_Media;
use WPDataAccess\WPDA;
class WPDA_Table extends WPDA_API_Core {
const WPDA_SEARCH_MODES = array(
'contains',
'startsWith',
'endsWith',
'equals',
'notEquals',
'empty',
'notEmpty',
'between',
'betweenInclusive',
'greaterThan',
'greaterThanOrEqualTo',
'lessThan',
'lessThanOrEqualTo'
);
public function register_rest_routes() {
register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/meta', array(
'methods' => array('POST'),
'callback' => array($this, 'table_meta'),
'permission_callback' => '__return_true',
'args' => array(
'dbs' => $this->get_param( 'dbs' ),
'tbl' => $this->get_param( 'tbl' ),
'waa' => array(
'required' => false,
'type' => 'boolean',
'description' => __( 'With admin actions (to support table exports)', 'wp-data-access' ),
),
),
) );
register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/select', array(
'methods' => array('GET', 'POST'),
'callback' => array($this, 'table_select'),
'permission_callback' => '__return_true',
'args' => array(
'dbs' => $this->get_param( 'dbs' ),
'tbl' => $this->get_param( 'tbl' ),
'col' => $this->get_param( 'cols' ),
'page_index' => $this->get_param( 'page_index' ),
'page_size' => $this->get_param( 'page_size' ),
'search' => $this->get_param( 'search' ),
'search_columns' => $this->get_param( 'search_columns' ),
'search_column_fns' => $this->get_param( 'search_column_fns' ),
'sorting' => $this->get_param( 'sorting' ),
'row_count' => $this->get_param( 'row_count' ),
'row_count_estimate' => $this->get_param( 'row_count_estimate' ),
'media' => $this->get_param( 'media' ),
),
) );
register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/get', array(
'methods' => array('GET', 'POST'),
'callback' => array($this, 'table_get'),
'permission_callback' => '__return_true',
'args' => array(
'dbs' => $this->get_param( 'dbs' ),
'tbl' => $this->get_param( 'tbl' ),
'key' => $this->get_param( 'key' ),
'media' => $this->get_param( 'media' ),
),
) );
register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/insert', array(
'methods' => array('GET', 'POST'),
'callback' => array($this, 'table_insert'),
'permission_callback' => '__return_true',
'args' => array(
'dbs' => $this->get_param( 'dbs' ),
'tbl' => $this->get_param( 'tbl' ),
'val' => $this->get_param( 'val' ),
),
) );
register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/update', array(
'methods' => array('GET', 'POST'),
'callback' => array($this, 'table_update'),
'permission_callback' => '__return_true',
'args' => array(
'dbs' => $this->get_param( 'dbs' ),
'tbl' => $this->get_param( 'tbl' ),
'key' => $this->get_param( 'key' ),
'val' => $this->get_param( 'val' ),
),
) );
register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/delete', array(
'methods' => array('GET', 'POST'),
'callback' => array($this, 'table_delete'),
'permission_callback' => '__return_true',
'args' => array(
'dbs' => $this->get_param( 'dbs' ),
'tbl' => $this->get_param( 'tbl' ),
'key' => $this->get_param( 'key' ),
),
) );
register_rest_route( WPDA_API::WPDA_NAMESPACE, 'table/lov', array(
'methods' => array('GET', 'POST'),
'callback' => array($this, 'table_lov'),
'permission_callback' => '__return_true',
'args' => array(
'dbs' => $this->get_param( 'dbs' ),
'tbl' => $this->get_param( 'tbl' ),
'col' => $this->get_param( 'col' ),
),
) );
}
/**
* Get table meta info.
*
* @param WP_REST_Request $request Rest API request.
* @return \WP_Error|\WP_REST_Response
*/
public function table_meta( $request ) {
$dbs = $request->get_param( 'dbs' );
$tbl = $request->get_param( 'tbl' );
$waa = $request->get_param( 'waa' );
if ( $this->check_table_access(
$dbs,
$tbl,
$request,
'select',
$msg
) ) {
return $this->WPDA_Rest_Response( '', $this->get_table_meta_data( $dbs, $tbl, $waa ) );
} else {
if ( 'rest_cookie_invalid_nonce' === $msg ) {
return $this->invalid_nonce();
} else {
return new \WP_Error('error', $msg, array(
'status' => 401,
));
}
}
}
/**
* Database table query using the full primary key. Must return exactly one row.
*
* @param WP_REST_Request $request Rest API request.
* @return \WP_Error|\WP_REST_Response
*/
public function table_get( $request ) {
$dbs = $request->get_param( 'dbs' );
$tbl = $request->get_param( 'tbl' );
$key = $request->get_param( 'key' );
$media = $request->get_param( 'media' );
if ( $this->check_table_access(
$dbs,
$tbl,
$request,
'select',
$msg
) ) {
return $this->get(
$dbs,
$tbl,
$key,
$media
);
} else {
if ( 'rest_cookie_invalid_nonce' === $msg ) {
return $this->invalid_nonce();
} else {
return new \WP_Error('error', $msg, array(
'status' => 401,
));
}
}
}
/**
* Insert one row.
*
* @param WP_REST_Request $request Rest API request.
* @return \WP_Error|\WP_REST_Response
*/
public function table_insert( $request ) {
$dbs = $request->get_param( 'dbs' );
$tbl = $request->get_param( 'tbl' );
$val = $request->get_param( 'val' );
if ( $this->check_table_access(
$dbs,
$tbl,
$request,
'insert',
$msg
) ) {
return $this->insert( $dbs, $tbl, $val );
} else {
if ( 'rest_cookie_invalid_nonce' === $msg ) {
return $this->invalid_nonce();
} else {
return new \WP_Error('error', $msg, array(
'status' => 401,
));
}
}
}
/**
* Update uses primary key. Must return exactly one row.
*
* @param WP_REST_Request $request Rest API request.
* @return \WP_Error|\WP_REST_Response
*/
public function table_update( $request ) {
$dbs = $request->get_param( 'dbs' );
$tbl = $request->get_param( 'tbl' );
$key = $request->get_param( 'key' );
$val = $request->get_param( 'val' );
if ( $this->check_table_access(
$dbs,
$tbl,
$request,
'update',
$msg
) ) {
return $this->update(
$dbs,
$tbl,
$key,
$val
);
} else {
if ( 'rest_cookie_invalid_nonce' === $msg ) {
return $this->invalid_nonce();
} else {
return new \WP_Error('error', $msg, array(
'status' => 401,
));
}
}
}
/**
* Delete uses primary key. Must return exactly one row.
*
* @param WP_REST_Request $request Rest API request.
* @return \WP_Error|\WP_REST_Response
*/
public function table_delete( $request ) {
$dbs = $request->get_param( 'dbs' );
$tbl = $request->get_param( 'tbl' );
$key = $request->get_param( 'key' );
if ( $this->check_table_access(
$dbs,
$tbl,
$request,
'delete',
$msg
) ) {
return $this->delete( $dbs, $tbl, $key );
} else {
if ( 'rest_cookie_invalid_nonce' === $msg ) {
return $this->invalid_nonce();
} else {
return new \WP_Error('error', $msg, array(
'status' => 401,
));
}
}
}
/**
* Database table query to populate a list of values for a specific table/column.
*
* @param WP_REST_Request $request Rest API request.
* @return \WP_Error|\WP_REST_Response
*/
public function table_lov( $request ) {
}
/**
* Database table query.
*
* Supports: searching, ordering and pagination.
*
* @param WP_REST_Request $request Rest API request.
* @return \WP_Error|\WP_REST_Response
*/
public function table_select( $request ) {
$dbs = $request->get_param( 'dbs' );
$tbl = $request->get_param( 'tbl' );
$col = $request->get_param( 'col' );
$page_index = $request->get_param( 'page_index' );
$page_size = $request->get_param( 'page_size' );
$search = $request->get_param( 'search' );
$search_columns = $request->get_param( 'search_columns' );
$search_column_fns = $request->get_param( 'search_column_fns' );
$sorting = $request->get_param( 'sorting' );
$row_count = $request->get_param( 'row_count' );
$row_count_estimate = $request->get_param( 'row_count_estimate' );
$media = $request->get_param( 'media' );
if ( $this->check_table_access(
$dbs,
$tbl,
$request,
'select',
$msg
) ) {
return $this->select(
$dbs,
$tbl,
$col,
$page_index,
$page_size,
$search,
$search_columns,
$search_column_fns,
$sorting,
$row_count,
$row_count_estimate,
$media
);
} else {
if ( 'rest_cookie_invalid_nonce' === $msg ) {
return $this->invalid_nonce();
} else {
return new \WP_Error('error', $msg, array(
'status' => 401,
));
}
}
}
/**
* Perform query and return result as JSON response.
*
* @param string $dbs Schema name (database).
* @param string $tbl Table Name.
* @param array $column_name Column name.
* @param array $search Global search.
* @param array $search_columns Column filters.
* @param array $search_column_fns Column filter fns.
* @return \WP_Error|\WP_REST_Response
*/
public function lov(
$dbs,
$tbl,
$column_name,
$cascade = false,
$default_where = '',
$search = '',
$column_names = array(),
$search_columns = array(),
$search_column_fns = array(),
$lookups = array(),
$md = array(),
$m2m_relationship = array(),
$search_data_types = array()
) {
}
public function lookup(
$dbs,
$tbl,
$column_key,
$column_value,
$column_dynamic_values,
$default_where,
$cascade = false,
$cascade_table = '',
$cascade_column = '',
$cascade_where = '',
$search = '',
$column_names = array(),
$search_columns = array(),
$search_column_fns = array(),
$lookups = array(),
$md = array(),
$m2m_relationship = array(),
$search_data_types = array()
) {
$wpdadb = WPDADB::get_db_connection( $dbs );
if ( null === $wpdadb ) {
// Error connecting.
return new \WP_Error('error', "Error connecting to database {$dbs}", array(
'status' => 420,
));
} else {
// Connected, perform queries.
$suppress = $wpdadb->suppress_errors( true );
$subquery = '';
$where = '';
if ( '' !== trim( $default_where ) ) {
if ( 'where' !== strtolower( substr( trim( $default_where ), 0, 5 ) ) ) {
$where = "where {$default_where}";
} else {
$where = $default_where;
}
}
$dynamic_where = array();
if ( is_array( $column_dynamic_values ) && 0 < count( $column_dynamic_values ) ) {
foreach ( $column_dynamic_values as $key => $value ) {
$dynamic_where[] = $wpdadb->prepare( " `{$key}` = %s ", $value );
}
$where .= (( '' === $where ? ' where ' : ' and ' )) . ' (' . implode( ' and ', $dynamic_where ) . ') ';
}
if ( strpos( $column_value, ',' ) !== false ) {
$columns = explode( ',', $column_value );
$sql = $wpdadb->prepare( "\n\t\t\t\t\t\t\tselect distinct `%1s` as 'key'\n\t\t\t\t\t\t\t, `%1s`\n\t\t\t\t\t\t\tfrom `%1s`\n\t\t\t\t\t\t", array($column_key, implode( '`,`', $columns ), $tbl) );
} else {
$sql = $wpdadb->prepare( "\n\t\t\t\t\t\t\tselect distinct `%1s` as 'key'\n\t\t\t\t\t\t\t, `%1s` as 'value' \n\t\t\t\t\t\t\tfrom `%1s`\n\t\t\t\t\t\t", array($column_key, $column_value, $tbl) );
}
$sql .= " {$where} order by 2 ";
// $where already sanitized
$dataset = $wpdadb->get_results( $sql, 'OBJECT' );
$wpdadb->suppress_errors( $suppress );
// Send response.
if ( '' === $wpdadb->last_error ) {
// Prepare debug info.
if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
$debug = array(
'debug' => array(
'sql' => preg_replace( "/\\s+/", " ", $sql ),
'where' => $where ?? '',
),
);
} else {
$debug = null;
}
// Add context node to response.
$context = array();
if ( isset( $debug['debug'] ) && 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
$context['debug'] = $debug['debug'];
}
return $this->WPDA_Rest_Response( '', $dataset, $context );
} else {
return new \WP_Error('error', $wpdadb->last_error, array(
'status' => 420,
));
}
}
}
/**
* Perform query and return result as JSON response.
*
* @param string $dbs Schema name (database).
* @param string $tbl Table Name.
* @param array $primary Primary (key|value pairs.
* @param array $media_columns Media columns.
* @param array $column_names Just a plain array containing the column names.
* @return \WP_Error|\WP_REST_Response
*/
public function get(
$dbs,
$tbl,
$primary_key,
$media_columns,
$column_names = array(),
$default_where = ''
) {
$wpdadb = WPDADB::get_db_connection( $dbs );
if ( null === $wpdadb ) {
// Error connecting.
return new \WP_Error('error', "Error connecting to database {$dbs}", array(
'status' => 420,
));
} else {
// Connected, perform queries.
$suppress = $wpdadb->suppress_errors( true );
$where = '';
foreach ( $primary_key as $primary_key_column => $primary_key_value ) {
$where = ( '' === $where ? ' where ' : $where . ' and ' );
$where .= $wpdadb->prepare( " `%1s` = %s ", array($primary_key_column, $primary_key_value) );
}
if ( '' !== $default_where ) {
if ( '' === $where ) {
$where = $default_where;
} else {
$where .= " and {$default_where} ";
}
}
$selected_columns = '*';
if ( 0 < count( $column_names ) ) {
$selected_columns = '`' . implode( '`,`', array_map( function ( $column_name ) {
return WPDA::remove_backticks( $column_name );
}, $column_names ) ) . '`';
}
$dataset = $wpdadb->get_results( $wpdadb->prepare( "\n\t\t\t\t\t\t\tselect {$selected_columns}\n\t\t\t\t\t\t\tfrom `%1s`\n\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t", array($tbl) ), 'ARRAY_A' );
// Prepare debug info.
if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
$debug = array(
'debug' => array(
'where' => $where,
),
);
} else {
$debug = null;
}
$wpdadb->suppress_errors( $suppress );
// Send response.
if ( 0 === count( $dataset ) ) {
return new \WP_Error('error', "No data found", array(
'status' => 420,
));
} elseif ( 1 === count( $dataset ) ) {
$media = array();
if ( 0 < count( $media_columns ) ) {
foreach ( $media_columns as $media_column_name => $media_column_type ) {
if ( isset( $dataset[0][$media_column_name] ) ) {
if ( in_array( $media_column_type, [
'WP-Image',
'WP-Attachment',
'WP-Audio',
'WP-Video'
] ) ) {
$media[$media_column_name] = WPDA_WP_Media::get_media_url( $dataset[0][$media_column_name] );
}
}
}
}
$context = array();
$context['media'] = $media;
if ( isset( $debug['debug'] ) && 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
$context['debug'] = $debug['debug'];
}
return $this->WPDA_Rest_Response( '', $dataset, $context );
} else {
return new \WP_Error('error', "Invalid arguments", array(
'status' => 420,
));
}
}
}
public function insert( $dbs, $tbl, $column_values ) {
$wpdadb = WPDADB::get_db_connection( $dbs );
if ( null === $wpdadb ) {
// Error connecting.
return new \WP_Error('error', "Error connecting to database {$dbs}", array(
'status' => 420,
));
} else {
// Sanitize column names and values.
$sanitized_column_values = self::sanitize_column_values( $dbs, $tbl, $column_values );
if ( false === $sanitized_column_values ) {
return new \WP_Error('error', "Invalid arguments", array(
'status' => 420,
));
}
// Insert row.
$rows_inserted = $wpdadb->insert( $tbl, $sanitized_column_values );
// Send response.
if ( 1 === $rows_inserted ) {
return $this->WPDA_Rest_Response( __( 'Row successfully inserted', 'wp-data-access' ), null, array(
'insert_id' => $wpdadb->insert_id,
) );
} else {
if ( '' !== $wpdadb->last_error ) {
return new \WP_Error('error', $wpdadb->last_error, array(
'status' => 420,
));
} else {
return new \WP_Error('error', 'Insert failed', array(
'status' => 420,
));
}
}
}
}
public function update(
$dbs,
$tbl,
$primary_key,
$column_values,
$column_names = array()
) {
$wpdadb = WPDADB::get_db_connection( $dbs );
if ( null === $wpdadb ) {
// Error connecting.
return new \WP_Error('error', "Error connecting to database {$dbs}", array(
'status' => 420,
));
} else {
// Sanitize column names and values.
$sanitized_column_values = self::sanitize_column_values( $dbs, $tbl, $column_values );
if ( false === $sanitized_column_values ) {
return new \WP_Error('error', "Invalid arguments", array(
'status' => 420,
));
}
// Update row.
$rows_inserted = $wpdadb->update( $tbl, $sanitized_column_values, $primary_key );
// Send response.
if ( 0 === $rows_inserted ) {
return $this->WPDA_Rest_Response_Info( 'Nothing to update' );
} elseif ( 1 === $rows_inserted ) {
$context = null;
if ( 0 < count( $column_names ) ) {
// Return updated values
$updated_row = $this->get(
$dbs,
$tbl,
$primary_key,
$column_names
);
if ( isset( $updated_row->data['data'][0] ) ) {
$updated_values = $updated_row->data['data'][0];
$updated_context = array();
foreach ( $updated_values as $key => $value ) {
if ( !isset( $column_values[$key] ) ) {
$updated_context[$key] = $value;
}
}
if ( 0 < count( $updated_context ) ) {
$context = array(
'updated' => $updated_context,
);
}
}
}
return $this->WPDA_Rest_Response( __( 'Row successfully updated', 'wp-data-access' ), null, $context );
} else {
if ( '' !== $wpdadb->last_error ) {
return new \WP_Error('error', $wpdadb->last_error, array(
'status' => 420,
));
} else {
return new \WP_Error('error', 'Update failed', array(
'status' => 420,
));
}
}
}
}
public function delete( $dbs, $tbl, $primary_key ) {
$wpdadb = WPDADB::get_db_connection( $dbs );
if ( null === $wpdadb ) {
// Error connecting.
return new \WP_Error('error', "Error connecting to database {$dbs}", array(
'status' => 420,
));
} else {
// Delete row.
$rows_deleted = $wpdadb->delete( $tbl, $primary_key );
// Send response.
if ( 0 === $rows_deleted ) {
return $this->WPDA_Rest_Response_Info( __( 'No data found', 'wp-data-access' ) );
} elseif ( 1 === $rows_deleted ) {
return $this->WPDA_Rest_Response( __( 'Row successfully deleted', 'wp-data-access' ) );
} else {
if ( '' !== $wpdadb->last_error ) {
return new \WP_Error('error', $wpdadb->last_error, array(
'status' => 420,
));
} else {
return new \WP_Error('error', 'Delete failed', array(
'status' => 420,
));
}
}
}
}
private function generate_lookup_condition(
$wpdadb,
$lookups,
$column_name,
$search_values,
$search_column_fns,
$filter_mode = null,
$filter_key = false
) {
$lookup = $lookups[$column_name];
$lookup_table = $lookup['tbl'];
$lookup_key = $lookup['key'];
$lookup_columns = explode( ',', $lookup['value'] );
$lookup_where = array();
if ( $filter_key ) {
$filter_columns = array($lookup_key);
} else {
$filter_columns = $lookup_columns;
}
foreach ( $filter_columns as $lookup_column ) {
foreach ( $search_values as $search_value ) {
$lookup_where[] = $this->add_filter(
$wpdadb,
$lookup_column,
( $filter_mode !== null ? $filter_mode : $search_column_fns[$column_name] ),
$search_value
);
}
}
if ( 0 < count( $lookup_where ) ) {
return $wpdadb->prepare( ' `%1s` in ( select `%1s` from `%1s` where (' . implode( ' or ', $lookup_where ) . ') ) ', array(
$column_name,
$lookup_key,
$lookup_table,
$lookup_columns[0],
"%{$search_values[0]}%"
) );
} else {
return null;
}
}
public static function remove_where_from_sql( $sql ) {
if ( 'where' === substr( trim( $sql ), 0, 5 ) ) {
$pos = strpos( $sql, 'where' );
if ( false !== $pos ) {
$sql = substr_replace(
$sql,
'',
$pos,
5
);
}
}
return $sql;
}
private function get_md( $md, $wpdadb, $m2m_relationship ) {
}
private function get_global_filter(
$wpdadb,
$search,
$column_names,
$lookups,
$m2m_relationship
) {
$where_global = array();
if ( null !== $search && "" !== $search ) {
foreach ( $column_names as $column_name => $queryable ) {
if ( $queryable ) {
if ( isset( $lookups[$column_name] ) ) {
// Perform look search.
$condition = $this->generate_lookup_condition(
$wpdadb,
$lookups,
$column_name,
array($search),
array(),
'contains'
);
if ( null !== $condition ) {
$where_global[] = $condition;
}
} else {
$where_global[] = $wpdadb->prepare( " `%1s` like '%s' ", array($this->convert_column_name( $m2m_relationship, $column_name ), '%' . esc_sql( $search ) . '%') );
}
}
}
}
return $where_global;
}
private function get_column_filters(
$wpdadb,
$search_columns,
$search_column_fns,
$lookups,
$m2m_relationship,
$search_data_types
) {
}
private function get_where(
$wpdadb,
$default_where,
$md,
$m2m_relationship,
$search,
$column_names,
$lookups,
$search_columns,
$search_column_fns,
$search_data_types
) {
// Default where.
if ( '' !== trim( $default_where ) && 'where' !== strtolower( substr( trim( $default_where ), 0, 5 ) ) ) {
$where = "where {$default_where}";
} else {
$where = $default_where;
}
// Global filter.
$where_global = $this->get_global_filter(
$wpdadb,
$search,
$column_names,
$lookups,
$m2m_relationship
);
if ( 0 < count( $where_global ) ) {
$where .= (( '' === trim( $where ) ? ' where ' : ' and ' )) . $this->add_condition( $where_global, 'or' );
}
return $where;
}
/**
* Perform query and return result as JSON response.
*
* @param string $dbs Schema name (database).
* @param string $tbl Table Name.
* @param string $column_names Column Names.
* @param string $page_index Page number.
* @param string $page_size Rows per page.
* @param string $search Filter.
* @param string $search_columns Column search filters.
* @param string $search_column_fns Column search filter modes.
* @param string $Sorting Order by.
* @param integer $last_row_count Row count previous request.
* @param string $row_count_estimate Indicates if row count estimate should be used.
* @param string $media_columns Media columns.
* @param string $default_where Defaul where clause
* @param string $default_orderby Defaul order by clause
* @return \WP_Error|\WP_REST_Response
*/
public function select(
$dbs,
$tbl,
$column_names,
$page_index,
$page_size,
$search,
$search_columns,
$search_column_fns,
$sorting,
$last_row_count,
$row_count_estimate,
$media_columns,
$default_where = '',
$default_orderby = '',
$lookups = array(),
$md = array(),
$m2m_relationship = array(),
$search_data_types = array()
) {
$wpdadb = WPDADB::get_db_connection( $dbs );
if ( null === $wpdadb ) {
// Error connecting.
return new \WP_Error('error', "Error connecting to database {$dbs}", array(
'status' => 420,
));
} else {
$suppress = $wpdadb->suppress_errors( true );
// Build where clause.
$where = $this->get_where(
$wpdadb,
$default_where,
$md,
$m2m_relationship,
$search,
$column_names,
$lookups,
$search_columns,
$search_column_fns,
$search_data_types
);
// Build order by.
$sqlorder = '';
if ( is_array( $sorting ) && 0 < count( $sorting ) ) {
foreach ( $sorting as $sort ) {
if ( '' === $sqlorder ) {
$sqlorder = 'order by ';
} else {
$sqlorder .= ',';
}
$sqlorder .= '`' . $this->convert_column_name( $m2m_relationship, $sort['id'] ) . '` ' . (( $sort['desc'] ? 'desc' : 'asc' ));
}
}
if ( '' === $sqlorder && '' !== trim( $default_orderby ) ) {
$sqlorder = $default_orderby;
}
// Add pagination.
if ( !is_numeric( $page_size ) ) {
$page_size = 10;
}
$offset = $page_index * $page_size;
// Calculate offset.
if ( !is_numeric( $offset ) ) {
$offset = 0;
}
// Prepare query.
$sql = "\n\t\t\t\t\tselect `" . implode( "`,`", array_keys( $column_names ) ) . "`\n\t\t\t\t\tfrom `%1s`\n\t\t\t\t\t{$where}\n\t\t\t\t\t{$sqlorder}\n\t\t\t\t";
$sql_tables = array($tbl);
// Prepare debug info.
if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
$debug = array(
'debug' => array(
'sql' => preg_replace( "/\\s+/", " ", $sql ),
'where' => $where,
'order by' => $sqlorder,
),
);
} else {
$debug = null;
}
// Perform query.
$dataset = $wpdadb->get_results( $wpdadb->prepare( $sql . (( 0 < $page_size ? " limit {$page_size} offset {$offset} " : '' )), $sql_tables ), 'ARRAY_A' );
if ( $wpdadb->last_error ) {
// Handle SQL errors.
return new \WP_Error('error', $wpdadb->last_error, array(
'status' => 420,
'debug' => ( isset( $debug['debug'] ) ? $debug : null ),
));
}
if ( is_numeric( $last_row_count ) and 0 <= $last_row_count ) {
// Prevents an extra query.
$rowcount = $last_row_count;
} else {
$estimate = false;
if ( '1' === $row_count_estimate && '' === $where ) {
// Perform row count estimate
$countrows = $wpdadb->get_results( $wpdadb->prepare( "\n\t\t\t\t\t\t\t\t\tselect table_rows as rowcount\n\t\t\t\t\t\t\t\t\t from information_schema.tables\n\t\t\t\t\t\t\t\t\twhere table_schema = %s\n\t\t\t\t\t\t\t\t\t and table_name = %s\n\t\t\t\t\t\t\t\t", [$wpdadb->dbname, $tbl] ), 'ARRAY_A' );
if ( isset( $countrows[0]['rowcount'] ) ) {
$estimate = true;
}
}
if ( !$estimate ) {
if ( !$estimate ) {
// (Re)Count rows.
$countrows = $wpdadb->get_results( $wpdadb->prepare( "\n\t\t\t\t\t\t\t\t\t\tselect count(1) as rowcount\n\t\t\t\t\t\t\t\t\t\tfrom `%1s`\n\t\t\t\t\t\t\t\t\t\t{$where}\n\t\t\t\t\t\t\t\t\t", array($tbl) ), 'ARRAY_A' );
}
}
if ( $wpdadb->last_error ) {
// Handle SQL errors.
return new \WP_Error('error', $wpdadb->last_error, array(
'status' => 420,
));
}
if ( isset( $countrows[0]['rowcount'] ) ) {
$rowcount = $countrows[0]['rowcount'];
} else {
$rowcount = 0;
}
}
// Add context node to response
$context = array();
if ( isset( $debug['debug'] ) && 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
$context['debug'] = $debug['debug'];
}
if ( 0 < count( $media_columns ) ) {
// Handle WP media library
$media = array();
for ($i = 0; $i < count( $dataset ); $i++) {
$media_row = array();
foreach ( $media_columns as $media_column_name => $media_column_type ) {
if ( isset( $dataset[$i][$media_column_name] ) ) {
$media_row[$media_column_name] = WPDA_WP_Media::get_media_url( $dataset[$i][$media_column_name] );
}
}
$media[] = $media_row;
}
// Add media to context node
$context['media'] = $media;
}
$wpdadb->suppress_errors( $suppress );
// Send response.
$response = $this->WPDA_Rest_Response(
'',
$dataset,
$context,
array(
'rowCount' => $rowcount,
)
);
$response->header( 'X-WP-Total', $rowcount );
// Total rows for this query.
if ( 0 < $page_size ) {
$pagecount = floor( $rowcount / $page_size );
if ( $pagecount != $rowcount / $page_size ) {
// phpcs:ignore WordPress.PHP.StrictComparisons
$pagecount++;
}
} else {
// Prevent division by zero
$pagecount = 0;
}
$response->header( 'X-WP-TotalPages', $pagecount );
// Total pages for this query.
return $response;
}
}
private function convert_column_name( $m2m_relationship, $column_name ) {
if ( 0 < count( $m2m_relationship ) ) {
// Map join table and relation table columns.
if ( 'd.' === substr( $column_name, 0, 2 ) ) {
return 'd`.`' . $this->sanitize_db_identifier( substr( $column_name, 2 ) );
} else {
return 'm`.`' . $this->sanitize_db_identifier( $column_name );
}
} else {
// Return plaing column name.
return $this->sanitize_db_identifier( $column_name );
}
}
private function map_columns( $prefix, $column_names ) {
return implode( ",", array_map( function ( $v ) use($prefix) {
$c = $this->sanitize_db_identifier( $v );
$r = ( 'd' === $prefix ? "d.{$c}" : $c );
return "`{$prefix}`.`{$c}` as \"{$r}\"";
}, array_keys( $column_names ) ) );
}
public function add_filter(
$wpdadb,
$search_column,
$search_column_fns,
$search_value,
$m2m_relationship = array(),
$search_data_types = array()
) {
}
public static function add_condition( $where_lines, $operand = 'and' ) {
if ( 0 < count( array_filter( $where_lines ) ) ) {
// Apply all searches.
return ' ( (' . implode( ") {$operand} (", array_filter( $where_lines ) ) . ') ) ';
} else {
return "";
}
}
/**
* Get table meta data.
*
* @param string $dbs Database schema name.
* @param string $tbl Database table name.
* @param string $waa With admin actions.
* @return array\object
*/
public function get_table_meta_data( $dbs, $tbl, $waa ) {
$sql_create_table = '';
if ( current_user_can( 'manage_options' ) ) {
// Admin user has access to all resources
$access = array(
'select' => array('POST'),
'insert' => array('POST'),
'update' => array('POST'),
'delete' => array('POST'),
);
// Get create table script
$wpdadb = WPDADB::get_db_connection( $dbs );
if ( null !== $wpdadb ) {
$suppress_errors = $wpdadb->suppress_errors;
$wpdadb->suppress_errors = true;
$wpdadb->query( "SET sql_mode = 'NO_TABLE_OPTIONS'" );
$sql = $wpdadb->get_results( $wpdadb->prepare( 'show create table `%1s`', array($tbl) ), 'ARRAY_N' );
if ( isset( $sql[0][1] ) ) {
$sql_create_table = $sql[0][1];
}
$wpdadb->suppress_errors = $suppress_errors;
}
} else {
$access = $this->get_table_access( $dbs, $tbl );
}
$settings = new stdClass();
if ( null !== $access ) {
$columns = WPDA_List_Columns_Cache::get_list_columns( $dbs, $tbl );
$settings_db = WPDA_Table_Settings_Model::query( $tbl, $dbs );
if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
$settings = json_decode( $settings_db[0]['wpda_table_settings'] );
// Remove old settings from response.
unset($settings->form_labels);
unset($settings->list_labels);
unset($settings->custom_settings);
unset($settings->search_settings);
}
$settings->ui = WPDA_Settings::get_admin_settings( $dbs, $tbl );
$rest_api = get_option( WPDA_API::WPDA_REST_API_TABLE_ACCESS );
if ( isset( $rest_api[$dbs][$tbl] ) ) {
$settings->rest_api = $rest_api[$dbs][$tbl];
}
$settings->env = $this->get_env();
$wp_nonce_action_alter = "wpda-alter-{$tbl}";
$wp_nonce_alter = wp_create_nonce( $wp_nonce_action_alter );
$wp_nonce_refresh = null;
$connect = null;
global $wpdb;
$settings->wp = [
'roles' => $this->get_wp_roles(),
'users' => $this->get_wp_users(),
'home' => admin_url( 'admin.php' ),
'homea' => admin_url( 'admin-ajax.php' ),
'tables' => array_values( $wpdb->tables() ),
'date_format' => get_option( 'date_format' ),
'time_format' => get_option( 'time_format' ),
'alter' => $wp_nonce_alter,
'refresh' => $wp_nonce_refresh,
'connect' => $connect,
];
if ( true === $waa ) {
$settings->wp['aonce'] = implode( '-', array(
wp_create_nonce( 'wpda-export-' . json_encode( $tbl ) ),
// Table export
wp_create_nonce( 'wpda-rename-' . $tbl ),
) );
}
$media = $this->get_media( $dbs, $tbl, $columns->get_table_columns() );
}
return array(
'columns' => $columns->get_table_columns(),
'table_labels' => $columns->get_table_header_labels(),
'form_labels' => $columns->get_table_column_headers(),
'primary_key' => $columns->get_table_primary_key(),
'access' => $access,
'settings' => $settings,
'media' => $media['media'],
'wp_media' => $media['wp_media'],
'table_info' => $this->get_table_info( $dbs, $tbl ),
'create' => $sql_create_table,
);
}
private function get_table_access( $dbs, $tbl ) {
if ( current_user_can( 'manage_options' ) ) {
// Check administrator rights
if ( is_admin() ) {
$access = WPDA_Dictionary_Access::check_table_access_backend( $dbs, $tbl, $done );
} else {
$access = WPDA_Dictionary_Access::check_table_access_frontend( $dbs, $tbl, $done );
}
if ( $access ) {
// Administrator access granted
return array(
'select' => array('POST'),
'insert' => array('POST'),
'update' => array('POST'),
'delete' => array('POST'),
);
}
}
$tables = get_option( WPDA_API::WPDA_REST_API_TABLE_ACCESS );
if ( false !== $tables && isset( $tables[$dbs][$tbl] ) && is_array( $tables[$dbs][$tbl] ) ) {
$table = $tables[$dbs][$tbl];
$table_access = new \stdClass();
$table_access->select = $this->get_table_access_action( $table, 'select' );
$table_access->insert = $this->get_table_access_action( $table, 'insert' );
$table_access->update = $this->get_table_access_action( $table, 'update' );
$table_access->delete = $this->get_table_access_action( $table, 'delete' );
return $table_access;
}
return false;
}
private function get_table_access_action( $table, $action ) {
if ( isset( $table[$action]['authorization'], $table[$action]['methods'] ) && is_array( $table[$action]['methods'] ) && 0 < count( $table[$action]['methods'] ) ) {
if ( 'anonymous' === $table[$action]['authorization'] ) {
return $table[$action]['methods'];
} else {
// Check authorized users
if ( isset( $table[$action]['authorized_users'] ) && is_array( $table[$action]['authorized_users'] ) && 0 < count( $table[$action]['authorized_users'] ) && in_array( (string) $this->get_user_login(), $table[$action]['authorized_users'] ) ) {
return $table[$action]['methods'];
}
// Check authorized roles
if ( isset( $table[$action]['authorized_roles'] ) && is_array( $table[$action]['authorized_roles'] ) && 0 < count( $table[$action]['authorized_roles'] ) && 0 < count( array_intersect( $this->get_user_roles(), $table[$action]['authorized_roles'] ) ) ) {
return $table[$action]['methods'];
}
}
}
return array();
}
/**
* Check if access is grant for requested database/table.
*
* @param string $dbs Remote or local database connection string.
* @param string $tbl Database table name.
* @param onject $request Request object.
* @param string $action Possible values: select, insert, update, delete.
* @return bool
*/
private function check_table_access(
$dbs,
$tbl,
$request,
$action,
&$msg = ''
) {
if ( current_user_can( 'manage_options' ) ) {
// Grant access to administrators always.
return true;
}
$tables = get_option( WPDA_API::WPDA_REST_API_TABLE_ACCESS );
if ( false === $tables ) {
// No tables.
$msg = __( 'Unauthorized', 'wp-data-access' );
return false;
}
if ( !(isset( $tables[$dbs][$tbl][$action]['methods'] ) && is_array( $tables[$dbs][$tbl][$action]['methods'] )) ) {
// No methods.
$msg = __( 'Unauthorized', 'wp-data-access' );
return false;
} else {
if ( !in_array( $request->get_method(), $tables[$dbs][$tbl][$action]['methods'] ) ) {
//phpcs:ignore - 8.1 proof
$msg = __( 'Unauthorized', 'wp-data-access' );
return false;
}
}
if ( !isset( $tables[$dbs][$tbl][$action]['authorization'] ) ) {
// No authorization.
$msg = __( 'Unauthorized', 'wp-data-access' );
return false;
} else {
if ( 'anonymous' === $tables[$dbs][$tbl][$action]['authorization'] ) {
// Access granted to all users.
return true;
}
}
global $wp_rest_auth_cookie;
if ( true !== $wp_rest_auth_cookie ) {
// No anonymous access.
$msg = __( 'Unauthorized', 'wp-data-access' );
return false;
} else {
if ( 'authorized' !== $tables[$dbs][$tbl][$action]['authorization'] ) {
// Authorization check.
$msg = __( 'Unauthorized', 'wp-data-access' );
return false;
}
// Authorized access requires a valid nonce.
if ( !wp_verify_nonce( $request->get_header( 'X-WP-Nonce' ), 'wp_rest' ) ) {
$msg = 'rest_cookie_invalid_nonce';
return false;
}
if ( !(isset( $tables[$dbs][$tbl][$action]['authorized_users'] ) && is_array( $tables[$dbs][$tbl][$action]['authorized_users'] )) ) {
// No users.
$msg = __( 'Unauthorized', 'wp-data-access' );
return false;
} else {
$requesting_user_login = $this->get_user_login();
if ( 0 < count( $tables[$dbs][$tbl][$action]['authorized_users'] ) && in_array( $requesting_user_login, $tables[$dbs][$tbl][$action]['authorized_users'] ) ) {
return true;
}
}
if ( !(isset( $tables[$dbs][$tbl][$action]['authorized_roles'] ) && is_array( $tables[$dbs][$tbl][$action]['authorized_roles'] )) ) {
// No roles.
$msg = __( 'Unauthorized', 'wp-data-access' );
return false;
} else {
$requesting_user_roles = $this->get_user_roles();
if ( false === $requesting_user_roles ) {
$requesting_user_roles = array();
}
if ( 0 < count( $tables[$dbs][$tbl][$action]['authorized_roles'] ) && 0 < count( array_intersect( $requesting_user_roles, $tables[$dbs][$tbl][$action]['authorized_roles'] ) ) ) {
return true;
}
}
$msg = __( 'Unauthorized', 'wp-data-access' );
return false;
}
}
private function sanitize_column_values( $dbs, $tbl, $column_values ) {
$wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $dbs, $tbl );
$sanitized_column_values = [];
foreach ( $column_values as $column_name => $column_value ) {
$column_value = $column_values[$column_name];
switch ( $wpda_list_columns->get_column_data_type( $column_name ) ) {
case 'tinytext':
case 'text':
case 'mediumtext':
case 'longtext':
if ( null !== $column_value ) {
$column_value = wp_kses_post( $column_value );
}
break;
default:
if ( null !== $column_value ) {
$column_value = sanitize_text_field( $column_value );
}
}
$sanitized_column_values[$this->sanitize_db_identifier( $column_name )] = $column_value;
}
return $sanitized_column_values;
}
}