PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.40
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.40
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_Import_Multi.php

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

443 lines 13.4 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\Dashboard\WPDA_Dashboard;
13 use WPDataAccess\WPDA;
14
15 /**
16 * Class WPDA_Import_Multi
17 *
18 * Imports a script file that might contain multiple SQL statement including create table and insert into
19 * statements.
20 *
21 * @author Peter Schulz
22 * @since 1.6.0
23 */
24 class WPDA_Import_Multi {
25
26 const SOLUTIONS = '(<a href="https://wpdataaccess.com/docs/tool-guide/known-limitations/" target="_blank">see solutions</a>)';
27
28 /**
29 * URL where to post data
30 *
31 * @var string
32 */
33 protected $url;
34
35 /**
36 * Database schema name
37 *
38 * @var string
39 */
40 protected $schema_name;
41
42 /**
43 * Pointer to import file
44 *
45 * @var string
46 */
47 protected $file_pointer;
48
49 /**
50 * Content of import file
51 *
52 * @var string
53 */
54 protected $file_content;
55
56 /**
57 * Text to inform user (line 1).
58 *
59 * @var string
60 */
61 protected $info_title = '';
62
63 /**
64 * Text to inform user (line 1).
65 *
66 * @var string
67 */
68 protected $info_text = '';
69
70 /**
71 * Indicicates whether ZipArchive is installed.
72 *
73 * @var bool
74 */
75 protected $isinstalled_ziparchive = false;
76
77 /**
78 * WPDA_Import constructor
79 *
80 * Checks if ZipArchive is installed to support the import of ZIP files.
81 *
82 * @param string $page Page where to post data (url).
83 * @param string $schema_name Database schema name.
84 * @param array $args Extra arguments.
85 *
86 * @since 1.6.0
87 */
88 public function __construct( $page, $schema_name, $args = null ) {
89 $this->url = $page;
90 $this->schema_name = $schema_name;
91
92 $this->isinstalled_ziparchive = class_exists( '\ZipArchive' );
93
94 if ( ! is_null( $args ) && isset( $args[0] ) && isset( $args[1] ) ) {
95 $this->info_title = $args[0];
96 $this->info_text = $args[1];
97 } else {
98 $this->info_title = __(
99 'IMPORT DATA/EXECUTE SCRIPT(S)',
100 'wp-data-access'
101 );
102 if ( $this->isinstalled_ziparchive ) {
103 $this->info_text = __(
104 'Supports <strong>sql</strong> and <strong>zip</strong> file types.',
105 'wp-data-access'
106 );
107 } else {
108 $this->info_text = __(
109 'Supports only file type <strong>sql</strong> (install <strong>ZipArchive</strong> for <strong>zip</strong> file type support).',
110 'wp-data-access'
111 );
112 }
113 }
114 }
115
116 /**
117 * Checks if request is valid and allowed
118 *
119 * If the requested import is valid and allowed, the import file is loaded and its content imported.
120 *
121 * @since 1.6.0
122 */
123 public function check_post() {
124 // Check if import was requested.
125 if (
126 isset( $_REQUEST['action'] ) &&
127 'import' === sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ) // input var okay.
128 ) {
129 // Security check.
130 $wp_nonce = isset( $_REQUEST['_wpnonceimport'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonceimport'] ) ) : '?'; // input var okay.
131 if ( ! wp_verify_nonce( $wp_nonce, 'wpda-import-from-data-explorer-' . WPDA::get_current_user_login() ) ) {
132 wp_die( __( 'ERROR: Not authorized', 'wp-data-access' ) );
133 }
134
135 if ( isset( $_FILES['filename'] ) ) {
136
137 // phpcs:disable
138 $temp_file_name = sanitize_text_field( $_FILES['filename']['tmp_name'] ); // For Windows: do NOT unslash!
139 // phpcs:enable
140 $temp_file_type = sanitize_text_field( wp_unslash( $_FILES['filename']['type'] ) );
141 $orig_file_name = sanitize_text_field( wp_unslash( $_FILES['filename']['name'] ) );
142
143 if ( 0 === $_FILES['filename']['error']
144 && is_uploaded_file( $temp_file_name )
145 ) {
146 if (
147 'application/zip' === $temp_file_type ||
148 'application/x-zip' === $temp_file_type ||
149 'application/x-zip-compressed' === $temp_file_type
150 ) {
151 // Process ZIP file.
152 if ( $this->isinstalled_ziparchive ) {
153 $zip = new \ZipArchive();
154 if ( $zip->open( $temp_file_name ) ) {
155 for ( $i = 0; $i < $zip->numFiles; $i ++ ) {
156 $this->file_pointer = $zip->getStream( $zip->getNameIndex( $i ) );
157 $this->import( $zip->getNameIndex( $i ) );
158 }
159 } else {
160 // Error reading ZIP file.
161 $this->import_failed( sprintf( __( 'Import failed [error reading ZIP file `%s`]', 'wp-data-access' ), $orig_file_name ) );
162 }
163 } else {
164 // ZipArchive not installed.
165 $this->import_failed( sprintf( __( 'Import failed - ZipArchive not installed %s', 'wp-data-access' ), self::SOLUTIONS ) );
166 }
167 } else {
168 // Process plain file.
169 $this->file_pointer = fopen( $temp_file_name, 'rb' );
170 $this->import( $orig_file_name );
171 }
172 }
173 } else {
174 $this->upload_failed();
175 }
176 } elseif ( isset( $_REQUEST['impchk'] ) ) {
177 $this->upload_failed();
178 }
179 }
180
181 /**
182 * Perform import
183 *
184 * Import file is read in chunks to allow imports of large files without resource limitations. An indicator
185 * is maintained to follow the progress of the import. The indicator is used to show a message at the end
186 * whether the import succeeded or failed.
187 *
188 * @param string $file_name Import file name
189 *
190 * @since 1.6.0
191 */
192 protected function import( $file_name ) {
193 // Check if errors should be shown.
194 $hide_errors = isset( $_REQUEST['hide_errors'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['hide_errors'] ) ) : 'off';
195
196 $result = true;
197 global $wpdb;
198
199 $wpdadb = WPDADB::get_db_connection( $this->schema_name );
200 if ( null === $wpdadb ) {
201 if ( is_admin() ) {
202 wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
203 } else {
204 die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) );
205 }
206 }
207
208 $suppress = $wpdadb->suppress_errors( 'on' === $hide_errors );
209
210 if ( false !== $this->file_pointer ) {
211 while ( ! feof( $this->file_pointer ) ) {
212 $this->file_content .= fread( $this->file_pointer, 4096 );
213
214 // Replace WP prefix and WPDA prefix.
215 $this->file_content = str_replace( '{wp_schema}', $wpdb->dbname, $this->file_content );
216 $this->file_content = str_replace( '{wp_prefix}', $wpdb->prefix, $this->file_content );
217 $this->file_content = str_replace( '{wpda_prefix}', 'wpda', $this->file_content ); // for backward compatibility
218
219 // Find and process SQL statements.
220 $sql_end_unix = strpos( $this->file_content, ";\n" );
221 $sql_end_windows = strpos( $this->file_content, ";\r\n" );
222 while ( false !== $sql_end_unix || false !== $sql_end_windows ) {
223 if ( false === $sql_end_unix ) {
224 $sql_end = $sql_end_windows;
225 } elseif ( false === $sql_end_windows ) {
226 $sql_end = $sql_end_unix;
227 } else {
228 $sql_end = min( $sql_end_unix, $sql_end_windows );
229 }
230 $sql = rtrim( substr( $this->file_content, 0, $sql_end ) );
231
232 $this->file_content = substr( $this->file_content, strpos( $this->file_content, $sql ) + strlen( $sql ) + 1 );
233
234 if ( false === $wpdadb->query( $sql ) ) {
235 $result = false;
236 }
237
238 // Find next SQL statement.
239 $sql_end_unix = strpos( $this->file_content, ";\n" );
240 $sql_end_windows = strpos( $this->file_content, ";\r\n" );
241 }
242 }
243 }
244
245 $wpdadb->suppress_errors( $suppress );
246
247 // Process file content.
248 if ( ! $result ) {
249 $this->import_failed( sprintf( __( 'Import `%s` failed [check import file]', 'wp-data-access' ), $file_name ) );
250 } else {
251 // Import succeeded.
252 $msg = new WPDA_Message_Box(
253 array(
254 'message_text' => sprintf( __( 'Import `%s` completed succesfully', 'wp-data-access' ), $file_name ),
255 )
256 );
257 $msg->box();
258 }
259 }
260
261 /**
262 * Inform user that an error occured
263 *
264 * @param string $msg Error message text
265 *
266 * @since 1.6.0
267 */
268 protected function import_failed( $msg ) {
269 $msg = new WPDA_Message_Box(
270 array(
271 'message_text' => $msg,
272 'message_type' => 'error',
273 'message_is_dismissible' => false,
274 )
275 );
276 $msg->box();
277 }
278
279 /**
280 * Inform user that the import failed
281 *
282 * @since 1.6.0
283 */
284 protected function upload_failed() {
285 $msg = new WPDA_Message_Box(
286 array(
287 'message_text' => sprintf( __( 'File upload failed %s', 'wp-data-access' ), self::SOLUTIONS ),
288 'message_type' => 'error',
289 'message_is_dismissible' => false,
290 )
291 );
292 $msg->box();
293 }
294
295 /**
296 * Adds an import button
297 *
298 * @param string $label Button label.
299 * @param string $class Button CSS class.
300 *
301 * @since 1.6.0
302 */
303 public function add_button( $label = '', $class = 'page-title-action' ) {
304 if ( '' === $label ) {
305 $label = __( 'Imports and scripts', 'wp-data-access' );
306 }
307 ?>
308 <a href="javascript:void(0)"
309 onclick="jQuery('#upload_file_container_multi').show()"
310 class="wpda_tooltip <?php echo esc_attr( $class ); ?>"
311 title="<?php echo __( 'Allows to import data and execute SQL scripts', 'wp-data-access' ); ?>.
312 <?php echo __( 'Add a ; and a new line character at the end of every SQL statement', 'wp-data-access' ); ?>"
313 >
314 <i class="fas fa-code wpda_icon_on_button"></i> <?php echo esc_attr( $label ); ?></a>
315 <?php
316 }
317
318 /**
319 * Adds an import container
320 *
321 * The container contains an upload form. The container is hidden by default. When the button created in
322 * {@see WPDA_Import_Multi::add_button()} is clicked, the container is shown.
323 *
324 * @since 1.6.0
325 */
326 public function add_container() {
327 $file_uploads_enabled = @ini_get( 'file_uploads' );
328 ?>
329
330 <script type='text/javascript'>
331 function before_submit_upload() {
332 if (jQuery('#filename').val() == '') {
333 alert('<?php echo __( 'No file to import!', 'wp-data-access' ); ?>');
334 return false;
335 }
336 if (!(jQuery('#filename')[0].files[0].size < <?php echo esc_attr( WPDA::convert_memory_to_decimal( @ini_get( 'upload_max_filesize' ) ) ); ?>)) {
337 alert("<?php echo __( 'File exceeds maximum size of', 'wp-data-access' ); ?> <?php echo esc_attr( @ini_get( 'upload_max_filesize' ) ); ?>!");
338 return false;
339 }
340 }
341 function activeTab(tabIndex) {
342 jQuery(".import_tab").hide();
343 jQuery(".nav-tab").removeClass("nav-tab-active");
344 jQuery("#import_tab-" + tabIndex).show();
345 jQuery("#import_tabs-" + tabIndex).addClass("nav-tab-active");
346 }
347 </script>
348
349 <div id="upload_file_container_multi" style="display: none">
350 <div>&nbsp;</div>
351 <div>
352 <div class="wpda_upload_container_dashboard">
353 <?php
354 if ( $file_uploads_enabled ) {
355 ?>
356 <form id="form_import_multi_table" method="post"
357 action="<?php echo esc_attr( $this->url ); ?>&impchk"
358 enctype="multipart/form-data">
359 <?php
360 echo $this->import_sql(); // phpcs:ignore WordPress.Security.EscapeOutput
361 ?>
362 </form>
363 <?php
364 } else {
365 ?>
366 <p>
367 <strong><?php echo __( 'ERROR', 'wp-data-access' ); ?></strong>
368 </p>
369 <p class="wpda_list_indent">
370 <?php
371 echo __( 'Your configuration does not allow file uploads!', 'wp-data-access' );
372 echo ' ';
373 echo __( 'Set', 'wp-data-access' );
374 echo ' <strong>';
375 echo __( 'file_uploads', 'wp-data-access' );
376 echo '</strong> ';
377 echo __( 'to', 'wp-data-access' );
378 echo ' <strong>';
379 echo __( 'On', 'wp-data-access' );
380 echo '</strong> (<a href="https://wpdataaccess.com/docs/tool-guide/known-limitations/">';
381 echo __( 'see documentation', 'wp-data-access' );
382 echo '</a>).';
383 ?>
384 </p>
385 <?php
386 }
387 ?>
388 </div>
389 </div>
390 <div>&nbsp;</div>
391 </div>
392 <?php
393 }
394
395 private function import_sql() {
396 if ( $this->isinstalled_ziparchive ) {
397 $file_extensions = '.sql,.zip';
398 } else {
399 $file_extensions = '.sql';
400 }
401 ?>
402 <p class="wpda_list_indent">
403 <?php
404 echo $this->info_text . ' ' . __( 'Maximum supported file size is', 'wp-data-access' ) . ' <strong>' . @ini_get( 'upload_max_filesize' ) . '</strong>. '; // phpcs:ignore WordPress.Security.EscapeOutput
405 ?>
406 </p>
407 <p class="wpda_list_indent">
408 <input type="file" name="filename" id="filename" class="wpda_tooltip"
409 accept="<?php echo esc_attr( $file_extensions ); ?>">
410 <label style="vertical-align:baseline;">
411 <input type="checkbox" name="hide_errors" style="vertical-align:sub;" checked>
412 <?php echo __( 'Hide errors', 'wp-data-access' ); ?>
413 </label>
414 </p>
415 <p class="wpda_list_indent">
416 <button type="submit"
417 class="button button-primary"
418 onclick="return before_submit_upload()">
419 <i class="fas fa-code wpda_icon_on_button"></i>
420 <?php echo __( 'Import file/Execute script(s)', 'wp-data-access' ); ?>
421 </button>
422 <a href="javascript:void(0)"
423 onclick="jQuery('#upload_file_container_multi').hide()"
424 class="button button-secondary">
425 <i class="fas fa-times-circle wpda_icon_on_button"></i>
426 <?php echo __( 'Cancel', 'wp-data-access' ); ?>
427 </a>
428 <input type="hidden" name="action" value="import">
429 <?php wp_nonce_field( 'wpda-import-from-data-explorer-' . WPDA::get_current_user_login(), '_wpnonceimport', false ); ?>
430 </p>
431 <p class="wpda_list_indent">
432 <?php
433 echo '<strong>' . __( 'IMPORTANT', 'wp-data-access' ) . '</strong> &minus; ' .
434 __( 'Add a ; and a new line character at the end of every SQL statement', 'wp-data-access' );
435 ?>
436 </p>
437 <?php
438 }
439
440 }
441
442 }
443