diff --git a/readme.txt b/readme.txt index c23cfe0..122954e 100644 --- a/readme.txt +++ b/readme.txt @@ -1,5 +1,5 @@ === SQL Executioner === -Contributors: justincwatt, olarmarius +Contributors: justincwatt, olarmarius, drahflow Donate link: http://justinsomnia.org/2008/02/the-wordpress-sql-executioner/ Tags: phpMyAdmin, MySQL, query, SQL, DBA, database, database administration, admin, CSV Requires at least: 3.0 @@ -29,6 +29,24 @@ https://github.com/justincwatt/wp-sql-executioner Extract the zip file, drop the sql-executioner folder in your wp-content/plugins/ directory, and then activate from the Plugins page. +== REST API == + +To enable API access to your SQL database, add a line to `wp-config.php`: + + define('SQLEXECUTIONER_KEY', ''); + +This will activate an API endpoint at + + /wp-json/sql-executioner/v1/result + +which accepts JSON-formatted SQL queries like this: + + wget -O - --header='Content-Type: application/json' --post-data='{"sql": "SELECT 1;", "time": , "hmac": ""}' 'http://your-domain.com/wp-json/sql-executioner/v1/result' + +and the HMAC is computed as + + $hmac = hash_hmac('sha256', time() . ":" . $sql, SQLEXECUTIONER_KEY); + == Frequently Asked Questions == = Does this plugin have any undo? = diff --git a/sql-executioner.php b/sql-executioner.php index 07d6508..0eeb1dc 100644 --- a/sql-executioner.php +++ b/sql-executioner.php @@ -2,9 +2,9 @@ /* Plugin Name: SQL Executioner Version: 1.4 -Plugin URI: http://justinsomnia.org/2008/02/the-wordpress-sql-executioner/ +Plugin URI: https://github.com/Drahflow/wp-sql-executioner Description: Execute SQL commands on your WordPress database. Goto Tools > SQL Executioner to operate. -Author: Justin Watt +Author: Justin Watt, modified by Drahflow Author URI: http://justinsomnia.org/ LICENSE @@ -36,9 +36,11 @@ public function __construct() { add_action( 'admin_init', array( $this, 'register_scripts') ); add_action( 'admin_menu', array( $this, 'add_admin_menu' ) ); + add_action( 'rest_api_init', array( $this, 'rest_api_init' ) ); // set up our own db connection so as to not interfer with WordPress' $this->db = mysqli_connect( DB_HOST, DB_USER, DB_PASSWORD, DB_NAME ); + mysqli_set_charset ( $this->db , 'utf8' ); // get list of tables and create dollar-sign shortcuts $rst = mysqli_query( $this->db, "show tables" ); @@ -121,4 +123,65 @@ public static function str_putcsv($input, $delimiter = ',', $enclosure = '"') { fclose( $fp ); return $data; } + + public function rest_api_init() { + $namespace = 'sql-executioner/v1'; + + register_rest_route($namespace, + '/result', + array( + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'rest_api_execute' ), + ), + ) + ); + } + + public function rest_api_execute( WP_REST_Request $request ) { + $json = $request->get_json_params(); + $sql = $json['sql']; + $hmac = $json['hmac']; + $timestamp = $json['time']; + + if ( !defined('SQLEXECUTIONER_KEY') ) { + return new WP_Error( 'rest_disabled', __( 'No access key is defined' ), array( 'status' => 403 ) ); + } + + if ( $timestamp < time() - 30 ) { + return new WP_Error( 'rest_invalid_hmac', __( 'Timestamp for HMAC too old' ), array( 'status' => 403 ) ); + } + + $expected_hmac = hash_hmac('sha256', $timestamp . ":" . $sql, SQLEXECUTIONER_KEY); + if ( $expected_hmac !== $hmac ) { + return new WP_Error( 'rest_invalid_hmac', __( 'Specified HMAC did not match' ), array( 'status' => 403 ) ); + } + + $results = array(); + $results['rows'] = array(); + $results['sql'] = $sql; + + if ( $rst = mysqli_query( $this->db, $sql ) ) { + + if ( preg_match( "/^\s*(alter|create|drop|rename|insert|delete|update|replace|truncate) /i", $sql ) ) { + $results['affected_rows'] = mysqli_affected_rows( $this->db ); + } else { + $first = true; + while ( $row = mysqli_fetch_assoc( $rst ) ) { + if ( $first ) { + $results['rows'][] = array_keys( $row ); + $first = false; + } + $results['rows'][] = array_values( $row ); + } + $results['columns'] = mysqli_fetch_fields( $rst ); + } + + $results['insert_id'] = mysqli_insert_id( $this->db ); + } else { + $results['error'] = mysqli_error( $this->db ); + } + + return $results; + } }