PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.84
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.84
5.5.84 5.5.83 5.5.82 5.5.81 5.5.80 5.5.79 5.5.77 5.5.76 5.5.75 5.5.73 5.5.72 5.5.22 5.5.23 5.5.29 5.5.3 5.5.31 5.5.32 5.5.34 5.5.35 5.5.36 5.5.37 5.5.4 5.5.40 5.5.41 5.5.42 All 160 releases
wp-data-access / WPDataAccess / Utilities / WPDA_Export_Formatted.php

WPDA_Export_Formatted.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.84, at WPDataAccess/Utilities/WPDA_Export_Formatted.php

367 lines 9.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Suppress "error - 0 - No summary was found for this file" on phpdoc generation
5 *
6 * @package WPDataAccess\Utilities
7 */
8
9 namespace WPDataAccess\Utilities {
10
11 use WPDataAccess\Connection\WPDADB;
12 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Exist;
13 use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model;
14 use WPDataAccess\Plugin_Table_Models\WPDP_Page_Model;
15 use WPDataAccess\WPDA;
16 use WPDataAccess\Data_Dictionary\WPDA_List_Columns_Cache;
17
18 /**
19 * Class WPDA_Export_Formatted
20 *
21 * This class should not be instantiated directly. Use it to built exports for specific types. Overwrite methods
22 * header, row and footer for your own type specific export.
23 *
24 * @author Peter Schulz
25 * @since 2.0.13
26 */
27 class WPDA_Export_Formatted {
28
29 /**
30 * Remote or local database connection
31 *
32 * @var null|object
33 */
34 protected $wpdadb = null;
35
36 /**
37 * Query
38 *
39 * Select statement used to perform export.
40 *
41 * @var string
42 */
43 protected $statement = '';
44
45 /**
46 * Database schema name
47 *
48 * @var string
49 */
50 protected $schema_name = '';
51
52 /**
53 * Database table name
54 *
55 * @var string
56 */
57 protected $table_names = '';
58
59 /**
60 * Project page id
61 *
62 * Helper to hide schema and table name in export links on web pages
63 *
64 * @var null
65 */
66 protected $pid = null;
67
68 /**
69 * Array containing selected rows
70 *
71 * @var null
72 */
73 protected $rows = null;
74
75 /**
76 * Number of rows found
77 *
78 * @var int
79 */
80 protected $row_count = 0;
81
82 /**
83 * Select columns
84 *
85 * @see WPDA_List_Columns::get_table_columns()
86 *
87 * @var array|null
88 */
89 protected $columns = null;
90
91 /**
92 * Column data types
93 *
94 * @var array
95 */
96 protected $data_types = array();
97
98 /**
99 * Primary key columns
100 *
101 * @var array
102 */
103 protected $table_primary_key = array();
104
105 /**
106 * Where clause added to query
107 *
108 * @var string
109 */
110 protected $where = '';
111
112 /**
113 * Handle to table columns
114 *
115 * @var object|null
116 */
117 protected $wpda_list_columns = null;
118
119 /**
120 * WPDA_Export_Formatted constructor.
121 *
122 * @since 2.0.13
123 */
124 public function __construct() {
125 if ( defined( 'WP_MAX_MEMORY_LIMIT' ) ) {
126 $wp_memory_limit = WP_MAX_MEMORY_LIMIT;
127 $current_memory_limit = @ini_get( 'memory_limit' );
128 if ( false === $current_memory_limit ||
129 WPDA::convert_memory_to_decimal( $current_memory_limit ) < WPDA::convert_memory_to_decimal( $wp_memory_limit )
130 ) {
131 @ini_set( 'memory_limit', $wp_memory_limit ); // phpcs:ignore
132 }
133 }
134 }
135
136 /**
137 * Main method to get arguments and start export.
138 *
139 * @since 2.0.13
140 */
141 public function export() {
142 if (!WPDA::current_user_is_admin()) {
143 return;
144 }
145
146 $this->table_names = isset( $_REQUEST['table_names'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['table_names'] ) ) : ''; // input var okay.
147 $this->pid = isset( $_REQUEST['pid'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['pid'] ) ) : ''; // input var okay.
148 if ( '' !== $this->table_names ) {
149 $wp_action = 'wpda-export-' . json_encode( $this->table_names );
150 if ( isset( $_REQUEST['wpdaschema_name'] ) ) {
151 $this->schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // input var okay.
152 }
153 } else {
154 $wp_action = "wpda-export-{$this->pid}";
155 }
156
157 // Check if export is allowed.
158 $wp_nonce = isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '?'; // input var okay.
159 if ( ! wp_verify_nonce( $wp_nonce, $wp_action ) ) {
160 wp_die();
161 }
162
163 if ( '' !== $this->pid ) {
164 $page = WPDP_Page_Model::get_page_from_page_id( $this->pid );
165 if ( false === $page ) {
166 wp_die();
167 }
168 $this->schema_name = $page[0]['page_schema_name'];
169 $this->table_names = $page[0]['page_table_name'];
170
171 } elseif ( isset( $_REQUEST['pid_default_where'] ) && is_numeric( $_REQUEST['pid_default_where'] ) ) {
172 $pid_default_where = sanitize_text_field( wp_unslash( $_REQUEST['pid_default_where'] ) ); // input var okay.
173 $page = WPDP_Page_Model::get_page_from_page_id( $pid_default_where );
174 WPDA::wpda_log_wp_error($pid_default_where);
175 if ( isset( $page[0]['page_where'] ) && '' !== trim( $page[0]['page_where'] ) ) {
176 $this->where .= '' === $this->where ? ' where ' : ' and ';
177 $this->where .= $page[0]['page_where'];
178 }
179 WPDA::wpda_log_wp_error($this->where);
180 }
181
182 // Check if table exists to prevent SQL injection.
183 $wpda_dictionary_exists = new WPDA_Dictionary_Exist( $this->schema_name, $this->table_names );
184 if ( ! $wpda_dictionary_exists->table_exists() ) {
185 wp_die();
186 }
187
188 // Check if table exists and access is granted.
189 $this->wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $this->schema_name, $this->table_names );
190 $this->columns = $this->wpda_list_columns->get_table_columns();
191 foreach ( $this->columns as $column ) {
192 $this->data_types[ $column['column_name'] ] = $column['data_type'];
193 }
194
195 // Get primary key columns.
196 $this->table_primary_key = $this->wpda_list_columns->get_table_primary_key();
197
198 // Check validity request. All primary key columns must be supplied. Return error if
199 // primary key columns are missing.
200 foreach ( $this->table_primary_key as $key ) {
201 if ( ! isset( $key ) ) {
202 wp_die();
203 }
204 }
205
206 if ( isset( $this->table_primary_key[0] ) && isset( $_REQUEST[ $this->table_primary_key[0] ] ) ) {
207 // Build where clause.
208 global $wpdb;
209 $count_pk = count( $_REQUEST[ $this->table_primary_key[0] ] ); // phpcs:ignore -- 8.1 proof
210 for ( $i = 0; $i < $count_pk; $i ++ ) {
211 $and = '';
212 foreach ( $this->table_primary_key as $key ) {
213 $and .= '' === $and ? '(' : ' and ';
214 if ( $this->is_numeric( $this->data_types[ $key ] ) ) {
215 $and .= $wpdb->prepare(
216 '`%1s` = %d', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
217 array(
218 WPDA::remove_backticks( $key ),
219 sanitize_text_field( wp_unslash( $_REQUEST[ $key ][ $i ] ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
220 )
221 );
222 } else {
223 $and .= $wpdb->prepare(
224 '`%1s` = %s', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
225 array(
226 WPDA::remove_backticks( $key ),
227 sanitize_text_field( wp_unslash( $_REQUEST[ $key ][ $i ] ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
228 )
229 );
230 }
231 }
232
233 $and .= '' === $and ? '' : ')';
234
235 $this->where .= '' === $this->where ? ' where ' : ' or ';
236 $this->where .= $and;
237 }
238 }
239
240 $this->prepare_sql();
241
242 $settings_db = WPDA_Table_Settings_Model::query( $this->table_names, $this->schema_name );
243 if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
244 $settings_db_custom = json_decode( $settings_db[0]['wpda_table_settings'] );
245 if ( isset( $settings_db_custom->table_settings->query_buffer_size ) ) {
246 $query_buffer_size = $settings_db_custom->table_settings->query_buffer_size;
247 } else {
248 $query_buffer_size = 0;
249 }
250 } else {
251 $query_buffer_size = 0;
252 }
253
254 if ( is_numeric( $query_buffer_size ) && $query_buffer_size > 0 ) {
255 // phpcs:disable Squiz.PHP.DiscouragedFunctions.Discouraged
256 set_time_limit(0);
257 // phpcs:enable Squiz.PHP.DiscouragedFunctions.Discouraged
258 $this->send_export_file_large( $query_buffer_size );
259 } else {
260 $this->send_export_file();
261 }
262 }
263
264 /**
265 * Prepare SQL query
266 *
267 * @since 2.0.13
268 */
269 protected function prepare_sql() {
270 $this->wpdadb = WPDADB::get_db_connection( $this->schema_name );
271 if ( null === $this->wpdadb ) {
272 if ( is_admin() ) {
273 /* translators: %s = database name */
274 wp_die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
275 } else {
276 /* translators: %s = database name */
277 die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
278 }
279 }
280
281 if ( '' === $this->schema_name ) {
282 $this->statement = "select * from `{$this->table_names}` {$this->where}";
283 } else {
284 $this->statement = "select * from `{$this->wpdadb->dbname}`.`{$this->table_names}` {$this->where}";
285 }
286 }
287
288 protected function send_export_file_large( $query_buffer_size ) {
289 $i = 0;
290 $sql = $this->statement . ' limit ' . $query_buffer_size;
291
292 $this->rows = $this->wpdadb->get_results( $sql, 'ARRAY_A' );
293 $this->row_count = $this->wpdadb->num_rows;
294
295 $this->header();
296
297 while ( $this->wpdadb->num_rows > 0 ) {
298 foreach ( $this->rows as $row ) {
299 $this->row( $row );
300 }
301
302 $i++;
303
304 $sql = $this->statement . ' limit ' . $query_buffer_size . ' offset ' . ($i*$query_buffer_size);
305 $this->rows = $this->wpdadb->get_results( $sql, 'ARRAY_A' );
306 $this->row_count += $this->wpdadb->num_rows;
307 }
308
309 $this->footer();
310
311 if ( null !== $this->pid ) {
312 die();
313 }
314 }
315
316 /**
317 * Send export file to browser
318 *
319 * @since 2.0.13
320 */
321 protected function send_export_file() {
322 $this->rows = $this->wpdadb->get_results( $this->statement, 'ARRAY_A' );
323 $this->row_count = $this->wpdadb->num_rows;
324
325 $this->header();
326 foreach ( $this->rows as $row ) {
327 $this->row( $row );
328 }
329 $this->footer();
330
331 if ( null !== $this->pid ) {
332 die();
333 }
334 }
335
336 /**
337 * Implement file header here
338 */
339 protected function header() { }
340
341 /**
342 * Implement how to process a row here
343 *
344 * @param $row
345 */
346 protected function row( $row ) { }
347
348 /**
349 * Implement file footer here
350 */
351 protected function footer() { }
352
353 /**
354 * Check if data type is numeric
355 *
356 * @param string $data_type Column data type
357 *
358 * @return bool TRUE = numeric
359 */
360 protected function is_numeric( $data_type ) {
361 return ( 'number' === WPDA::get_type( $data_type ) );
362 }
363
364 }
365
366 }
367