wpdb = $wpdb; } // ------------------------------------------------------------------------- // Export // ------------------------------------------------------------------------- /** * Build the export payload as an associative array. * * @return array */ public function build_export() { $payload = array( 'plugin' => 'kgv-verein-manager', 'version' => KGVVM_VERSION, 'exported' => gmdate( 'Y-m-d\TH:i:s\Z' ), 'tables' => array(), ); foreach ( self::$table_keys as $key ) { $table = Schema::table( $key ); if ( '' === $table ) { continue; } // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $rows = $this->wpdb->get_results( "SELECT * FROM {$table}", ARRAY_A ); $payload['tables'][ $key ] = is_array( $rows ) ? $rows : array(); } return $payload; } /** * Send the export as a JSON file download and exit. * * @return void */ public function send_download() { $payload = $this->build_export(); $json = wp_json_encode( $payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE ); $filename = 'kgvvm-export-' . gmdate( 'Y-m-d' ) . '.json'; nocache_headers(); header( 'Content-Type: application/json; charset=utf-8' ); header( 'Content-Disposition: attachment; filename="' . $filename . '"' ); header( 'Content-Length: ' . strlen( $json ) ); echo $json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped exit; } // ------------------------------------------------------------------------- // Import // ------------------------------------------------------------------------- /** * Validate and import data from a decoded JSON array. * * Returns an array with keys 'imported' (int[]), 'skipped' (string[]), 'errors' (string[]). * * @param array $payload Decoded JSON payload. * @return array */ public function import( array $payload ) { $result = array( 'imported' => array(), 'skipped' => array(), 'errors' => array(), ); if ( empty( $payload['plugin'] ) || 'kgv-verein-manager' !== $payload['plugin'] ) { $result['errors'][] = __( 'Die Datei stammt nicht vom KGV Verein Manager Plugin.', KGVVM_TEXT_DOMAIN ); return $result; } if ( empty( $payload['tables'] ) || ! is_array( $payload['tables'] ) ) { $result['errors'][] = __( 'Die Exportdatei enthält keine Tabellendaten.', KGVVM_TEXT_DOMAIN ); return $result; } // Wrap everything in a transaction so a partial failure can be rolled back. $this->wpdb->query( 'SET FOREIGN_KEY_CHECKS = 0' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $this->wpdb->query( 'START TRANSACTION' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery // Truncate in reverse dependency order. foreach ( array_reverse( self::$table_keys ) as $key ) { if ( ! isset( $payload['tables'][ $key ] ) ) { continue; } $table = Schema::table( $key ); if ( '' === $table ) { continue; } // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery $this->wpdb->query( "TRUNCATE TABLE {$table}" ); } // Re-insert in dependency order. foreach ( self::$table_keys as $key ) { if ( ! isset( $payload['tables'][ $key ] ) ) { $result['skipped'][] = $key; continue; } $table = Schema::table( $key ); if ( '' === $table ) { $result['skipped'][] = $key; continue; } $rows = (array) $payload['tables'][ $key ]; $count = 0; foreach ( $rows as $row ) { if ( ! is_array( $row ) || empty( $row ) ) { continue; } // Sanitize keys – only allow simple column names. $clean = array(); foreach ( $row as $col => $val ) { $col_clean = preg_replace( '/[^a-zA-Z0-9_]/', '', (string) $col ); if ( '' !== $col_clean ) { $clean[ $col_clean ] = $val; } } $inserted = $this->wpdb->insert( $table, $clean ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery if ( false !== $inserted ) { $count++; } else { $result['errors'][] = sprintf( /* translators: 1: table key 2: DB error */ __( 'Fehler beim Einfügen in %1$s: %2$s', KGVVM_TEXT_DOMAIN ), $key, (string) $this->wpdb->last_error ); } } $result['imported'][ $key ] = $count; } if ( empty( $result['errors'] ) ) { $this->wpdb->query( 'COMMIT' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery } else { $this->wpdb->query( 'ROLLBACK' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery } $this->wpdb->query( 'SET FOREIGN_KEY_CHECKS = 1' ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery return $result; } }