PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.80
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.80
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.80, at WPDataAccess/Utilities/WPDA_Export_Formatted.php

363 lines 9.7 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 $this->table_names = isset( $_REQUEST['table_names'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['table_names'] ) ) : ''; // input var okay.
143 $this->pid = isset( $_REQUEST['pid'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['pid'] ) ) : ''; // input var okay.
144 if ( '' !== $this->table_names ) {
145 $wp_action = 'wpda-export-' . json_encode( $this->table_names );
146 if ( isset( $_REQUEST['wpdaschema_name'] ) ) {
147 $this->schema_name = sanitize_text_field( wp_unslash( $_REQUEST['wpdaschema_name'] ) ); // input var okay.
148 }
149 } else {
150 $wp_action = "wpda-export-{$this->pid}";
151 }
152
153 // Check if export is allowed.
154 $wp_nonce = isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '?'; // input var okay.
155 if ( ! wp_verify_nonce( $wp_nonce, $wp_action ) ) {
156 wp_die();
157 }
158
159 if ( '' !== $this->pid ) {
160 $page = WPDP_Page_Model::get_page_from_page_id( $this->pid );
161 if ( false === $page ) {
162 wp_die();
163 }
164 $this->schema_name = $page[0]['page_schema_name'];
165 $this->table_names = $page[0]['page_table_name'];
166
167 } elseif ( isset( $_REQUEST['pid_default_where'] ) && is_numeric( $_REQUEST['pid_default_where'] ) ) {
168 $pid_default_where = sanitize_text_field( wp_unslash( $_REQUEST['pid_default_where'] ) ); // input var okay.
169 $page = WPDP_Page_Model::get_page_from_page_id( $pid_default_where );
170 WPDA::wpda_log_wp_error($pid_default_where);
171 if ( isset( $page[0]['page_where'] ) && '' !== trim( $page[0]['page_where'] ) ) {
172 $this->where .= '' === $this->where ? ' where ' : ' and ';
173 $this->where .= $page[0]['page_where'];
174 }
175 WPDA::wpda_log_wp_error($this->where);
176 }
177
178 // Check if table exists to prevent SQL injection.
179 $wpda_dictionary_exists = new WPDA_Dictionary_Exist( $this->schema_name, $this->table_names );
180 if ( ! $wpda_dictionary_exists->table_exists() ) {
181 wp_die();
182 }
183
184 // Check if table exists and access is granted.
185 $this->wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $this->schema_name, $this->table_names );
186 $this->columns = $this->wpda_list_columns->get_table_columns();
187 foreach ( $this->columns as $column ) {
188 $this->data_types[ $column['column_name'] ] = $column['data_type'];
189 }
190
191 // Get primary key columns.
192 $this->table_primary_key = $this->wpda_list_columns->get_table_primary_key();
193
194 // Check validity request. All primary key columns must be supplied. Return error if
195 // primary key columns are missing.
196 foreach ( $this->table_primary_key as $key ) {
197 if ( ! isset( $key ) ) {
198 wp_die();
199 }
200 }
201
202 if ( isset( $this->table_primary_key[0] ) && isset( $_REQUEST[ $this->table_primary_key[0] ] ) ) {
203 // Build where clause.
204 global $wpdb;
205 $count_pk = count( $_REQUEST[ $this->table_primary_key[0] ] ); // phpcs:ignore -- 8.1 proof
206 for ( $i = 0; $i < $count_pk; $i ++ ) {
207 $and = '';
208 foreach ( $this->table_primary_key as $key ) {
209 $and .= '' === $and ? '(' : ' and ';
210 if ( $this->is_numeric( $this->data_types[ $key ] ) ) {
211 $and .= $wpdb->prepare(
212 '`%1s` = %d', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
213 array(
214 WPDA::remove_backticks( $key ),
215 sanitize_text_field( wp_unslash( $_REQUEST[ $key ][ $i ] ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
216 )
217 );
218 } else {
219 $and .= $wpdb->prepare(
220 '`%1s` = %s', // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders
221 array(
222 WPDA::remove_backticks( $key ),
223 sanitize_text_field( wp_unslash( $_REQUEST[ $key ][ $i ] ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
224 )
225 );
226 }
227 }
228
229 $and .= '' === $and ? '' : ')';
230
231 $this->where .= '' === $this->where ? ' where ' : ' or ';
232 $this->where .= $and;
233 }
234 }
235
236 $this->prepare_sql();
237
238 $settings_db = WPDA_Table_Settings_Model::query( $this->table_names, $this->schema_name );
239 if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
240 $settings_db_custom = json_decode( $settings_db[0]['wpda_table_settings'] );
241 if ( isset( $settings_db_custom->table_settings->query_buffer_size ) ) {
242 $query_buffer_size = $settings_db_custom->table_settings->query_buffer_size;
243 } else {
244 $query_buffer_size = 0;
245 }
246 } else {
247 $query_buffer_size = 0;
248 }
249
250 if ( is_numeric( $query_buffer_size ) && $query_buffer_size > 0 ) {
251 // phpcs:disable Squiz.PHP.DiscouragedFunctions.Discouraged
252 set_time_limit(0);
253 // phpcs:enable Squiz.PHP.DiscouragedFunctions.Discouraged
254 $this->send_export_file_large( $query_buffer_size );
255 } else {
256 $this->send_export_file();
257 }
258 }
259
260 /**
261 * Prepare SQL query
262 *
263 * @since 2.0.13
264 */
265 protected function prepare_sql() {
266 $this->wpdadb = WPDADB::get_db_connection( $this->schema_name );
267 if ( null === $this->wpdadb ) {
268 if ( is_admin() ) {
269 /* translators: %s = database name */
270 wp_die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
271 } else {
272 /* translators: %s = database name */
273 die( sprintf( esc_attr__( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
274 }
275 }
276
277 if ( '' === $this->schema_name ) {
278 $this->statement = "select * from `{$this->table_names}` {$this->where}";
279 } else {
280 $this->statement = "select * from `{$this->wpdadb->dbname}`.`{$this->table_names}` {$this->where}";
281 }
282 }
283
284 protected function send_export_file_large( $query_buffer_size ) {
285 $i = 0;
286 $sql = $this->statement . ' limit ' . $query_buffer_size;
287
288 $this->rows = $this->wpdadb->get_results( $sql, 'ARRAY_A' );
289 $this->row_count = $this->wpdadb->num_rows;
290
291 $this->header();
292
293 while ( $this->wpdadb->num_rows > 0 ) {
294 foreach ( $this->rows as $row ) {
295 $this->row( $row );
296 }
297
298 $i++;
299
300 $sql = $this->statement . ' limit ' . $query_buffer_size . ' offset ' . ($i*$query_buffer_size);
301 $this->rows = $this->wpdadb->get_results( $sql, 'ARRAY_A' );
302 $this->row_count += $this->wpdadb->num_rows;
303 }
304
305 $this->footer();
306
307 if ( null !== $this->pid ) {
308 die();
309 }
310 }
311
312 /**
313 * Send export file to browser
314 *
315 * @since 2.0.13
316 */
317 protected function send_export_file() {
318 $this->rows = $this->wpdadb->get_results( $this->statement, 'ARRAY_A' );
319 $this->row_count = $this->wpdadb->num_rows;
320
321 $this->header();
322 foreach ( $this->rows as $row ) {
323 $this->row( $row );
324 }
325 $this->footer();
326
327 if ( null !== $this->pid ) {
328 die();
329 }
330 }
331
332 /**
333 * Implement file header here
334 */
335 protected function header() { }
336
337 /**
338 * Implement how to process a row here
339 *
340 * @param $row
341 */
342 protected function row( $row ) { }
343
344 /**
345 * Implement file footer here
346 */
347 protected function footer() { }
348
349 /**
350 * Check if data type is numeric
351 *
352 * @param string $data_type Column data type
353 *
354 * @return bool TRUE = numeric
355 */
356 protected function is_numeric( $data_type ) {
357 return ( 'number' === WPDA::get_type( $data_type ) );
358 }
359
360 }
361
362 }
363