Database
Inspect the WordPress database with flexible read-only SQL, and, when you opt in, perform structured, parameterized writes. The 3 read tools are enabled by default; the 3 write tools ship disabled-by-default (an admin opts in on EMCP Tools → Tools). All six require manage_options.
Direct DB access. The read path (
query) is bounded by a read-only-SQL validator that rejects writes, DDL, stacked statements, MySQL/*! … */executable comments, and file-access SQL (INTO OUTFILE/LOAD_FILE). Writes are structured and parameterized via$wpdb(no raw write-SQL, so no DDL), refusewp_users/wp_usermeta, force a non-empty WHERE on update/delete, and snapshot a before-image to an audit log. Arbitrary DB access is contrary to WordPress.org plugin guidelines; this feature exists per an explicit project decision and stays off unless you enable it.
Read tools (enabled by default)
Section titled “Read tools (enabled by default)”emcp-tools/list-tables
Section titled “emcp-tools/list-tables”List all tables in the WordPress database with row counts and sizes. Read-only (manage_options).
emcp-tools/describe-table
Section titled “emcp-tools/describe-table”Return the column definitions and indexes for a table. Read-only (manage_options).
emcp-tools/query
Section titled “emcp-tools/query”Run a read-only SQL query: SELECT / SHOW / DESCRIBE / EXPLAIN only; results are capped at 1,000 rows. Writes, DDL, stacked statements, /*! executable comments, and file-access SQL are rejected. It also refuses reads that touch wp_users/wp_usermeta (password hashes, session tokens, activation keys) — a protected_read error — even for a plain SELECT; use list-users/get-user for user data instead. Read-only (manage_options).
Hardened in v3.13.0. The guard was rebuilt around a real SQL tokenizer, not a string pattern-match, closing several bypasses a security review found (a comment trick, a backslash inside a string, a backquoted alias, a double-quoted identifier — each could hide a table name from the old check). A query is analyzed under every way the server could read it and refused if any reading is unsafe. Since 3.13.0, query also refuses:
- The server’s own system schemas:
mysql,information_schema,performance_schema,sys(protected_read, same error code and filter,emcp_tools_db_protected_tables, as the user-table refusal above). - Variable assignment (
:=) inside the query — that’s a write in disguise (not_read_only). - Delay/lock functions:
SLEEP,BENCHMARK,GET_LOCK, and similar (unsafe_function_blocked).
Row limiting is enforced by the database itself now, not by fetching everything and slicing in PHP: a query with no top-level LIMIT gets one added; a LIMIT larger than 1,000 is refused (limit_too_large) rather than silently capped; and a LIMIT that only appears inside a subquery doesn’t count as bounding the outer query. Each query also runs under a 10-second server-side statement timeout.
Write tools (disabled by default)
Section titled “Write tools (disabled by default)”Every write tool uses $wpdb with parameterized values (no raw write-SQL or DDL), refuses wp_users/wp_usermeta, and records a before-image snapshot to an audit log. The refused-table list (wp_users/wp_usermeta by default) is the same one the read-only query tool checks above, both filterable via emcp_tools_db_protected_tables.
emcp-tools/insert-row
Section titled “emcp-tools/insert-row”Insert a row into a table using $wpdb (manage_options).
emcp-tools/update-rows
Section titled “emcp-tools/update-rows”Update rows matching a forced non-empty WHERE clause; captures a before-image (manage_options).
emcp-tools/delete-rows
Section titled “emcp-tools/delete-rows”Delete rows matching a forced non-empty WHERE clause. Requires an explicit confirm:true; captures a before-image (manage_options).
Enabling the write tools
Section titled “Enabling the write tools”insert-row, update-rows, and delete-rows are off until you enable them. Open EMCP Tools → Tools in wp-admin, find the Database category on the WordPress tab, and toggle the ones you want. See Disabling tools.