PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.27
Booktics – Appointment Booking Calendar for Service Businesses v1.0.27
1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.2 1.0.3 All 31 releases
← All changes | base/abstracts/booktics-database.php +44 -10 1.0.0 → 1.0.27 View file →
@@ -31,8 +31,33 @@
31 31 $this->db = $wpdb;
32 32 }
33 33
34 34 /**
35 + * Validate a SQL identifier (column name) against a strict allow-list.
36 + *
37 + * Only plain identifiers ([A-Za-z0-9_]) are permitted. Since column names
38 + * cannot be parameterized by wpdb::prepare(), any value used as a column
39 + * name must be validated here to prevent SQL injection when the array keys
40 + * originate from user-controlled request bodies.
41 + *
42 + * @param string $identifier
43 + *
44 + * @return string The validated identifier, wrapped in backticks.
45 + *
46 + * @throws RuntimeException When the identifier is not a plain column name.
47 + */
48 + private function sanitize_identifier( string $identifier ): string {
49 + if ( ! preg_match( '/^[a-zA-Z0-9_]+$/', $identifier ) ) {
50 + throw new RuntimeException(
51 + /* translators: %s: column name. */
52 + sprintf( esc_html__( 'Invalid database column identifier: %s', 'booktics' ), esc_html( $identifier ) )
53 + );
54 + }
55 +
56 + return "`{$identifier}`";
57 + }
58 +
59 + /**
35 60 * Begin database transaction
36 61 *
37 62 * @return void
38 63 */
@@ -66,14 +91,14 @@
66 91 *
67 92 * @return void
68 93 */
69 94 public function delete( string $table, array $where ): void {
70 - $table = $this->db->prefix . $table;
95 + $table = booktics_get_table_name( $table );
71 96 $conditions = array();
72 97 $values = array();
73 98
74 99 foreach ( $where as $key => $value ) {
75 - $conditions[] = "$key = %s";
100 + $conditions[] = $this->sanitize_identifier( $key ) . ' = %s';
76 101 $values[] = $value;
77 102 }
78 103
79 104 $condition_string = implode( ' AND ', $conditions );
@@ -104,10 +129,11 @@
104 129 if ( empty( $records ) ) {
105 130 return;
106 131 }
107 132
108 - $table = $this->db->prefix . $table;
133 + $table = booktics_get_table_name( $table );
109 134 $columns = array_keys( $records[0] );
135 + $safe_columns = array_map( array( $this, 'sanitize_identifier' ), $columns );
110 136 $placeholders = array_fill( 0, count( $columns ), '%s' );
111 137 $placeholder_string = '(' . implode( ',', $placeholders ) . ')';
112 138
113 139 $values = array();
@@ -119,9 +145,9 @@
119 145 $values[] = $record[ $column ] ?? '';
120 146 }
121 147 }
122 148
123 - $column_string = implode( ',', $columns );
149 + $column_string = implode( ',', $safe_columns );
124 150 $placeholders_string = implode( ',', $placeholders_groups );
125 151
126 152 $sql = "INSERT INTO $table ($column_string) VALUES $placeholders_string";
127 153
@@ -144,10 +170,18 @@
144 170 *
145 171 * @return array
146 172 */
147 173 public function select( string $table, array $where = array(), array $columns = array( '*' ) ) {
148 - $table = $this->db->prefix . $table;
149 - $columns_s = implode( ', ', $columns );
174 + $table = booktics_get_table_name( $table );
175 + $columns_s = implode(
176 + ', ',
177 + array_map(
178 + function ( $column ) {
179 + return '*' === $column ? '*' : $this->sanitize_identifier( $column );
180 + },
181 + $columns
182 + )
183 + );
150 184 $sql = "SELECT $columns_s FROM $table";
151 185
152 186 $values = array();
153 187 if ( ! empty( $where ) ) {
@@ -153,9 +187,9 @@
153 187 if ( ! empty( $where ) ) {
154 188 $conditions = array();
155 189
156 190 foreach ( $where as $key => $value ) {
157 - $conditions[] = "$key = %s";
191 + $conditions[] = $this->sanitize_identifier( $key ) . ' = %s';
158 192 $values[] = $value;
159 193 }
160 194
161 195 $condition_string = implode( ' AND ', $conditions );
@@ -195,20 +229,20 @@
195 229 *
196 230 * @return void
197 231 */
198 232 public function update( string $table, array $data, array $where ) {
199 - $table = $this->db->prefix . $table;
233 + $table = booktics_get_table_name( $table );
200 234 $set_values = array();
201 235 $where_conditions = array();
202 236 $values = array();
203 237
204 238 foreach ( $data as $key => $value ) {
205 - $set_values[] = "$key = %s";
239 + $set_values[] = $this->sanitize_identifier( $key ) . ' = %s';
206 240 $values[] = $value;
207 241 }
208 242
209 243 foreach ( $where as $key => $value ) {
210 - $where_conditions[] = "$key = %s";
244 + $where_conditions[] = $this->sanitize_identifier( $key ) . ' = %s';
211 245 $values[] = $value;
212 246 }
213 247
214 248 $set_string = implode( ', ', $set_values );