config = $config; $this->progress = $progress; $this->outputDir = rtrim($outputDir, '/\\') . '/db/'; if (!is_dir($this->outputDir)) { wp_mkdir_p($this->outputDir); } } /** * Tablo listesini hazırlar */ public function prepareTables(): array { global $wpdb; // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Dynamic table name // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- INFO query $tables = $wpdb->get_col("SHOW TABLES LIKE '{$wpdb->prefix}%'"); // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared $this->tables = []; foreach ($tables as $table) { // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter $count = (int) $wpdb->get_var("SELECT COUNT(*) FROM `{$table}`"); $this->tables[$table] = [ 'name' => $table, 'rows' => $count, 'chunks' => (int) ceil($count / $this->config->getDbRowsPerChunk()), 'exported' => false ]; } return $this->tables; } /** * Bir chunk export eder * * @param int $tableIndex Tablo indeksi * @param int $offset Başlangıç satırı * @return array Sonraki chunk bilgisi veya null */ public function exportChunk(int $tableIndex, int $offset): ?array { global $wpdb; $tableNames = array_keys($this->tables); if (!isset($tableNames[$tableIndex])) { return null; // Tüm tablolar bitti } $table = $tableNames[$tableIndex]; $limit = $this->config->getDbRowsPerChunk(); // Veriyi çek // phpcs:disable WordPress.DB.DirectDatabaseQuery // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Dynamic table name $rows = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$table}` LIMIT %d OFFSET %d", $limit, $offset ), ARRAY_A ); // phpcs:enable if (empty($rows)) { // Bu tablo bitti, sonraki tabloya geç return [ 'table_index' => $tableIndex + 1, 'offset' => 0, 'completed_table' => $table ]; } // SQL dosyası oluştur $chunkNumber = (int) floor($offset / $limit) + 1; $filename = sprintf('%s_%03d.sql', $table, $chunkNumber); $filepath = $this->outputDir . $filename; $sql = $this->generateSql($table, $rows); file_put_contents($filepath, $sql); // Sonraki chunk $newOffset = $offset + count($rows); $tableInfo = $this->tables[$table]; if ($newOffset >= $tableInfo['rows']) { // Tablo bitti return [ 'table_index' => $tableIndex + 1, 'offset' => 0, 'completed_table' => $table ]; } return [ 'table_index' => $tableIndex, 'offset' => $newOffset, 'file' => $filename ]; } /** * SQL INSERT statement oluşturur */ private function generateSql(string $table, array $rows): string { global $wpdb; if (empty($rows)) { return ''; } $columns = array_keys($rows[0]); $columnList = '`' . implode('`, `', $columns) . '`'; $sql = "-- Table: {$table}\n"; $sql .= "-- Exported: " . gmdate('Y-m-d H:i:s') . "\n\n"; $batchSize = $this->config->getSqlBatchSize(); $batch = []; // WP Cloner özel encoding marker'ları // % karakteri SQL ve PHP'de sorun çıkarabilir, bu yüzden encode ediyoruz $specialChars = [ '%' => '{{WPCLONER_PERCENT}}', ]; foreach ($rows as $i => $row) { $values = []; foreach ($row as $value) { if ($value === null) { $values[] = 'NULL'; } else { // Özel karakterleri encode et $encoded = $value; foreach ($specialChars as $char => $marker) { $encoded = str_replace($char, $marker, $encoded); } $values[] = "'" . esc_sql($encoded) . "'"; } } $batch[] = '(' . implode(', ', $values) . ')'; if (count($batch) >= $batchSize || $i === count($rows) - 1) { $sql .= "INSERT INTO `{$table}` ({$columnList}) VALUES\n"; $sql .= implode(",\n", $batch) . ";\n\n"; $batch = []; } } return $sql; } /** * Tablo yapısını export eder */ public function exportTableStructures(): string { global $wpdb; $filepath = $this->outputDir . '_schema.sql'; $sql = "-- WP Cloner Database Schema\n"; $sql .= "-- Exported: " . gmdate('Y-m-d H:i:s') . "\n\n"; foreach (array_keys($this->tables) as $table) { // phpcs:disable WordPress.DB.DirectDatabaseQuery // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Variable table name // phpcs:disable WordPress.DB.DirectDatabaseQuery.SchemaChange // phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter -- Checked via SHOW TABLES $create = $wpdb->get_row("SHOW CREATE TABLE `{$table}`", ARRAY_A); // phpcs:enable if ($create && isset($create['Create Table'])) { $sql .= "DROP TABLE IF EXISTS `{$table}`;\n"; $sql .= $create['Create Table'] . ";\n\n"; } } file_put_contents($filepath, $sql); return $filepath; } public function getTables(): array { return $this->tables; } public function getTableCount(): int { return count($this->tables); } public function getTotalRows(): int { return array_sum(array_column($this->tables, 'rows')); } /** * Resume pointer'dan tablo listesini geri yükler */ public function setTables(array $tables): void { $this->tables = $tables; } }