mirror of
https://github.com/Heretek-AI/heretek-control-core.git
synced 2026-10-11 21:09:58 +00:00
Addresses the first SonarCloud analysis on PR #1 (128 new-code findings). Genuine issues are fixed in code; convention/style rules (camelCase naming php:S100/S101/S116, too-many-returns php:S1142) and the standalone test harnesses are handled via the SonarCloud profile + sonar-project.properties because snake_case + WP_Error guards are the WordPress conventions here. Security: - connector: transfer ids are now whitelisted ([A-Za-z0-9_-]{8,64}) and rejected before any path use; the residual S2083 path-build findings (the resume-keyed store must use the id) carry NOSONAR + rationale after the HMAC gate + strict validation. Complexity (php:S3776) - extracted helpers so no function sits far over the raised threshold: - connector: search_replace -> data_tables/text_columns/rewrite_rows; restore_archive -> restore_db; import -> run_dump_statement. - migrate-abilities: execute_migrate -> push_archive_packets/packet_error/ push_finalize/poll_job. - db-importer: run_statement helper (per-statement execution shared with the trailing no-';' fragment). - restore-engine: restore() -> restore_database(); append_log() dropped its unused $filename parameter. - char-state-machine extractors (extract_statement x2) carry NOSONAR + rationale. Other: - packager: .emcp extension -> const EXT; add_files split into file_iterator/ dir_is_skipped/zip_relative_name. - db-exporter: removed unused $col_ph. - migrate module: single-arg nonces (WP default _wpnonce, matching the view), page-URL helper, dropped unused $back params. - page-migrate view: single-arg wp_nonce_field(). - restore-engine + serialized-search-replace: tabs -> spaces. - sonar-project.properties: exclude tests/** + vendor/** (test harnesses mirror WP core function names by design). Tests: tests/test-migrate-packager.php 8 suites still green; php -l clean. Co-Authored-By: Claude <[email protected]>
181 lines
8.4 KiB
PHP
181 lines
8.4 KiB
PHP
<?php
|
|
/**
|
|
* Backup & Migrate admin view.
|
|
*
|
|
* Pure presentation — every action posts to the module's admin-post handler
|
|
* (EMCP_Tools_Migrate_Module::ADMIN_ACTION), so a page refresh never re-runs a
|
|
* restore or delete. Restore is deliberately admin-only.
|
|
*
|
|
* @package EMCP_Tools
|
|
* @since 3.12.0
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) { exit; }
|
|
|
|
if ( ! class_exists( 'EMCP_Tools_Migrate_Module' ) ) {
|
|
return;
|
|
}
|
|
$emcp_action = EMCP_Tools_Migrate_Module::ADMIN_ACTION;
|
|
$emcp_notice = EMCP_Tools_Migrate_Module::consume_notice();
|
|
|
|
if ( ! class_exists( 'ZipArchive' ) ) {
|
|
echo '<div class="notice notice-warning"><p>' . esc_html__( 'The PHP ZipArchive extension is not installed on this server. Backups cannot be created or restored.', 'emcp-tools' ) . '</p></div>';
|
|
}
|
|
|
|
$emcp_backups = class_exists( 'EMCP_Tools_Packager' ) ? EMCP_Tools_Packager::list_archives() : array();
|
|
$emcp_log = class_exists( 'EMCP_Tools_Restore_Engine' ) ? EMCP_Tools_Restore_Engine::get_log() : array();
|
|
|
|
if ( $emcp_notice ) {
|
|
$emcp_class = ( 'success' === $emcp_notice['type'] ) ? 'notice-success' : 'notice-error';
|
|
echo '<div class="notice ' . esc_attr( $emcp_class ) . ' is-dismissible"><p>' . esc_html( $emcp_notice['message'] ) . '</p></div>';
|
|
}
|
|
?>
|
|
|
|
<div class="emcp-migrate">
|
|
<h2><?php esc_html_e( 'Backup, Sync & Migrate', 'emcp-tools' ); ?></h2>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Create portable .emcp archives of this site (database + optional files), restore them, or push them to a live site running the EMCP connector. Restoring replaces the current database with the archive — use with care.', 'emcp-tools' ); ?>
|
|
</p>
|
|
|
|
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin: 12px 0;">
|
|
<input type="hidden" name="action" value="emcp_tools_download_connector">
|
|
<?php wp_nonce_field( $emcp_action ); ?>
|
|
<p>
|
|
<button type="submit" class="button"><?php esc_html_e( 'Download Connector Plugin', 'emcp-tools' ); ?></button>
|
|
<span class="description">
|
|
<?php esc_html_e( 'Install this small plugin on the destination site, define EMCP_CONNECTOR_SECRET there, then use emcp-tools/migrate-site to push.', 'emcp-tools' ); ?>
|
|
</span>
|
|
</p>
|
|
</form>
|
|
|
|
<div class="postbox" style="margin-top: 20px; max-width: 760px;">
|
|
<div class="postbox-header">
|
|
<h3 class="hndle"><?php esc_html_e( 'Create Archive', 'emcp-tools' ); ?></h3>
|
|
</div>
|
|
<div class="inside">
|
|
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
|
|
<input type="hidden" name="action" value="<?php echo esc_attr( $emcp_action ); ?>">
|
|
<input type="hidden" name="emcp_migrate_action" value="create">
|
|
<?php wp_nonce_field( $emcp_action ); ?>
|
|
<p>
|
|
<label for="emcp_backup_name"><?php esc_html_e( 'Archive name (optional):', 'emcp-tools' ); ?></label><br>
|
|
<input type="text" name="backup_name" id="emcp_backup_name" class="regular-text" placeholder="e.g. pre-redesign-backup">
|
|
</p>
|
|
<p>
|
|
<label>
|
|
<input type="checkbox" name="include_files" value="1">
|
|
<?php esc_html_e( 'Also bundle site files (uploads / plugins / themes). Larger archives, slower to create.', 'emcp-tools' ); ?>
|
|
</label>
|
|
</p>
|
|
<p>
|
|
<button type="submit" class="button button-primary"><?php esc_html_e( 'Create .emcp Archive', 'emcp-tools' ); ?></button>
|
|
</p>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="postbox" style="margin-top: 20px;">
|
|
<div class="postbox-header">
|
|
<h3 class="hndle"><?php esc_html_e( 'Existing Archives', 'emcp-tools' ); ?> (<?php echo count( $emcp_backups ); ?>)</h3>
|
|
</div>
|
|
<div class="inside">
|
|
<?php if ( empty( $emcp_backups ) ) : ?>
|
|
<p><em><?php esc_html_e( 'No archives created yet.', 'emcp-tools' ); ?></em></p>
|
|
<?php else : ?>
|
|
<table class="widefat striped">
|
|
<thead>
|
|
<tr>
|
|
<th><?php esc_html_e( 'Filename', 'emcp-tools' ); ?></th>
|
|
<th><?php esc_html_e( 'Size', 'emcp-tools' ); ?></th>
|
|
<th><?php esc_html_e( 'Created', 'emcp-tools' ); ?></th>
|
|
<th><?php esc_html_e( 'Actions', 'emcp-tools' ); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ( $emcp_backups as $emcp_b ) : ?>
|
|
<tr>
|
|
<td><strong><?php echo esc_html( $emcp_b['filename'] ); ?></strong></td>
|
|
<td><?php echo esc_html( $emcp_b['size'] ); ?></td>
|
|
<td><?php echo esc_html( $emcp_b['date'] ); ?></td>
|
|
<td>
|
|
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:inline-block;">
|
|
<input type="hidden" name="action" value="<?php echo esc_attr( $emcp_action ); ?>">
|
|
<input type="hidden" name="emcp_migrate_action" value="download">
|
|
<input type="hidden" name="archive" value="<?php echo esc_attr( $emcp_b['filename'] ); ?>">
|
|
<?php wp_nonce_field( $emcp_action ); ?>
|
|
<button type="submit" class="button"><?php esc_html_e( 'Download', 'emcp-tools' ); ?></button>
|
|
</form>
|
|
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:inline-block;"
|
|
onsubmit="return confirm('<?php echo esc_js( __( 'Restore replaces the current database (and files if present) with this archive. Continue?', 'emcp-tools' ) ); ?>');">
|
|
<input type="hidden" name="action" value="<?php echo esc_attr( $emcp_action ); ?>">
|
|
<input type="hidden" name="emcp_migrate_action" value="restore">
|
|
<input type="hidden" name="archive" value="<?php echo esc_attr( $emcp_b['filename'] ); ?>">
|
|
<?php wp_nonce_field( $emcp_action ); ?>
|
|
<button type="submit" class="button button-primary"><?php esc_html_e( 'Restore', 'emcp-tools' ); ?></button>
|
|
</form>
|
|
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:inline-block;"
|
|
onsubmit="return confirm('<?php echo esc_js( __( 'Delete this archive permanently?', 'emcp-tools' ) ); ?>');">
|
|
<input type="hidden" name="action" value="<?php echo esc_attr( $emcp_action ); ?>">
|
|
<input type="hidden" name="emcp_migrate_action" value="delete">
|
|
<input type="hidden" name="archive" value="<?php echo esc_attr( $emcp_b['filename'] ); ?>">
|
|
<?php wp_nonce_field( $emcp_action ); ?>
|
|
<button type="submit" class="button button-link-delete"><?php esc_html_e( 'Delete', 'emcp-tools' ); ?></button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if ( ! empty( $emcp_log ) ) : ?>
|
|
<div class="postbox" style="margin-top: 20px;">
|
|
<div class="postbox-header">
|
|
<h3 class="hndle"><?php esc_html_e( 'Restore History', 'emcp-tools' ); ?></h3>
|
|
</div>
|
|
<div class="inside">
|
|
<table class="widefat striped">
|
|
<thead>
|
|
<tr>
|
|
<th><?php esc_html_e( 'Time', 'emcp-tools' ); ?></th>
|
|
<th><?php esc_html_e( 'Archive', 'emcp-tools' ); ?></th>
|
|
<th><?php esc_html_e( 'Result', 'emcp-tools' ); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ( $emcp_log as $emcp_entry ) : ?>
|
|
<tr>
|
|
<td><?php echo esc_html( isset( $emcp_entry['time'] ) ? $emcp_entry['time'] : '' ); ?></td>
|
|
<td><?php echo esc_html( isset( $emcp_entry['filename'] ) ? $emcp_entry['filename'] : '' ); ?></td>
|
|
<td>
|
|
<?php
|
|
$emcp_parts = array();
|
|
if ( ! empty( $emcp_entry['db'] ) && isset( $emcp_entry['db']['errors'] ) ) {
|
|
$emcp_parts[] = sprintf( /* translators: 1: executed, 2: errors. */ __( 'DB %1$d stmts, %2$d errors', 'emcp-tools' ), (int) $emcp_entry['db']['executed'], (int) $emcp_entry['db']['errors'] );
|
|
}
|
|
if ( ! empty( $emcp_entry['search_replace']['rows'] ) ) {
|
|
$emcp_parts[] = sprintf( /* translators: %d: rewritten rows. */ __( '%d URL rewrites', 'emcp-tools' ), (int) $emcp_entry['search_replace']['rows'] );
|
|
}
|
|
if ( ! empty( $emcp_entry['files_placed'] ) ) {
|
|
$emcp_parts[] = sprintf( /* translators: %d: files placed. */ __( '%d files placed', 'emcp-tools' ), (int) $emcp_entry['files_placed'] );
|
|
}
|
|
if ( empty( $emcp_parts ) && empty( $emcp_entry['errors'] ) ) {
|
|
$emcp_parts[] = __( 'OK', 'emcp-tools' );
|
|
}
|
|
if ( ! empty( $emcp_entry['errors'] ) ) {
|
|
$emcp_parts[] = __( 'with errors', 'emcp-tools' );
|
|
}
|
|
echo esc_html( implode( ' — ', $emcp_parts ) );
|
|
?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|