Issues (65)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/DB/Database.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * This file contains only a single class.
4
 *
5
 * @file
6
 * @package Tabulate
7
 */
8
9
namespace WordPress\Tabulate\DB;
10
11
/**
12
 * The database class represents the entire MySQL database that WordPress uses.
13
 */
14
class Database {
15
16
	/**
17
	 * The global wpdb object.
18
	 *
19
	 * @var \wpdb
20
	 */
21
	protected $wpdb;
22
23
	/**
24
	 * A list of all table names.
25
	 *
26
	 * @var string[]
27
	 */
28
	protected $table_names;
29
30
	/**
31
	 * The filesystem.
32
	 *
33
	 * @var \WP_Filesystem_Base
34
	 */
35
	protected $filesystem;
36
37
	/**
38
	 * The list of all tables that the user can read.
39
	 *
40
	 * @var Table[]
41
	 */
42
	protected $tables;
43
44
	/**
45
	 * Create a new Database object based on the given wpdb object.
46
	 *
47
	 * @param \wpdb $wpdb The global wpdb object.
48
	 */
49
	public function __construct( $wpdb ) {
50
		$this->wpdb = $wpdb;
51
	}
52
53
	/**
54
	 * Set the filesystem.
55
	 *
56
	 * @param \WP_Filesystem_Base $filesystem The filesystem object.
57
	 */
58
	public function set_filesystem( \WP_Filesystem_Base $filesystem ) {
59
		$this->filesystem = $filesystem;
60
	}
61
62
	/**
63
	 * Get the filesystem.
64
	 *
65
	 * @return \WP_Filesystem_Base
66
	 */
67
	public function get_filesystem() {
68
		return $this->filesystem;
69
	}
70
71
	/**
72
	 * Get the global wpdb object.
73
	 *
74
	 * @return \wpdb
75
	 */
76
	public function get_wpdb() {
77
		return $this->wpdb;
78
	}
79
80
	/**
81
	 * Get a list of tables and views that the current user can read.
82
	 *
83
	 * @return string[] The table names.
84
	 */
85
	public function get_table_names() {
86
		if ( ! $this->table_names ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->table_names of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
87
			$this->table_names = array();
88
			foreach ( $this->wpdb->get_col( 'SHOW TABLES' ) as $table_name ) {
89
				if ( Grants::current_user_can( Grants::READ, $table_name ) ) {
90
					$this->table_names[ $table_name ] = $table_name;
91
				}
92
			}
93
		}
94
		return $this->table_names;
95
	}
96
97
	/**
98
	 * Get a table from the database.
99
	 *
100
	 * @param string $name The name of the desired table.
101
	 * @return \WordPress\Tabulate\DB\Table|false The table, or false if it's not available.
102
	 */
103
	public function get_table( $name ) {
104
		if ( ! in_array( $name, $this->get_table_names(), true ) ) {
105
			return false;
106
		}
107
		if ( ! isset( $this->tables[ $name ] ) ) {
108
			$this->tables[ $name ] = new Table( $this, $name );
109
		}
110
		return $this->tables[ $name ];
111
	}
112
113
	/**
114
	 * Forget all table information, forcing it to be re-read from the database
115
	 * when next required. Used after schema changes.
116
	 */
117
	public function reset() {
118
		$this->table_names = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type array<integer,string> of property $table_names.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
119
		$this->tables = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type array<integer,object<Wor...ess\Tabulate\DB\Table>> of property $tables.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
120
	}
121
122
	/**
123
	 * Get all tables in this database.
124
	 *
125
	 * @param boolean $exclude_views Whether to exclude database views from the returned list.
126
	 * @return Table[] An array of all Tables.
127
	 */
128
	public function get_tables( $exclude_views = true ) {
129
		$out = array();
130
		foreach ( $this->get_table_names() as $name ) {
131
			$table = $this->get_table( $name );
132
			// If this table is not available, skip it.
133
			if ( ! $table ) {
134
				continue;
135
			}
136
			if ( $exclude_views && $table->is_view() ) {
137
				continue;
138
			}
139
			$out[ $table->get_name() ] = $table;
140
		}
141
		return $out;
142
	}
143
144
	/**
145
	 * Get all views in this database.
146
	 *
147
	 * @return Table|array An array of all Tables that are views.
148
	 */
149
	public function get_views() {
150
		$out = array();
151
		foreach ( $this->get_tables( false ) as $table ) {
152
			if ( $table->is_view() ) {
153
				$out[ $table->get_name() ] = $table;
154
			}
155
		}
156
		return $out;
157
	}
158
159
	/**
160
	 * Create a new table.
161
	 *
162
	 * @param string $name The name of the new table.
163
	 * @param string $comment The table comment.
164
	 * @throws Exception If the current user cannot 'promote_users'.
165
	 */
166
	public function create_table( $name, $comment = '' ) {
167
		if ( ! current_user_can( 'promote_users' ) ) {
168
			throw new Exception( 'Only administrators are allowed to create tables' );
169
		}
170
		$sql = "CREATE TABLE IF NOT EXISTS `$name` ( "
171
			. " `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY "
172
			. ") ENGINE=InnoDB, COMMENT='$comment';";
173
		$this->query( $sql );
174
		$this->reset();
175
		return $this->get_table( $name );
176
	}
177
178
	/**
179
	 * A wrapper around wpdb::prepare() and wpdb::query()
180
	 * that also checks wpdb::$last_error and throws up on occasion of badness.
181
	 *
182
	 * @param string   $sql The SQL statement to execute.
183
	 * @param string[] $params Parameters to pass to wpdb::prepare().
184
	 * @param string   $error_message What to tell the user if this query fails.
185
	 * @throws Exception The exception message is taken from wpdb::$last_error and if WP_DEBUG is set will also include the erroneous SQL.
186
	 */
187
	public function query( $sql, $params = null, $error_message = null ) {
188
		if ( $params ) {
189
			$sql = $this->get_wpdb()->prepare( $sql, $params );
190
		}
191
		$this->get_wpdb()->query( $sql );
192
		if ( ! empty( $this->get_wpdb()->last_error ) ) {
193
			$msg = $error_message . ': ' . $this->get_wpdb()->last_error;
194
			if ( WP_DEBUG ) {
195
				$msg .= " <code>$sql</code>";
196
			}
197
			throw new Exception( $msg );
198
		}
199
	}
200
201
	/**
202
	 * Get the name of the directory to which MySQL will write temporary export files.
203
	 * This is either the value of the 'secure_file_priv' server variable,
204
	 * or WordPress's normal temporary directory as returned by get_temp_dir().
205
	 * Always has a trailing slash.
206
	 *
207
	 * @return string Full path of the directory.
208
	 * @throws Exception If the directory is not writable.
209
	 */
210
	public function get_tmp_dir() {
211
		$query = "SHOW VARIABLES LIKE 'secure_file_priv';";
212
		$db_dir = $this->get_wpdb()->get_var( $query, 1 );
213
		$dir = empty( $db_dir ) ? get_temp_dir() : $db_dir;
214
		$out = rtrim( $dir, '/' ) . '/';
215
		if ( ! $this->get_filesystem()->is_writable( $out ) ) {
216
			throw new Exception( "Unable to write to temporary directory $out" );
217
		}
218
		return $out;
219
	}
220
}
221