Changeset 3715166
- Timestamp:
- 09/27/2026 08:38:16 AM (4 weeks ago)
- Location:
- one-click-migration
- Files:
-
- 10 edited
- 1 copied
-
tags/0.5.0 (copied) (copied from one-click-migration/trunk )
-
tags/0.5.0/clickpress-migration.php (modified) (2 diffs)
-
tags/0.5.0/consts.php (modified) (1 diff)
-
tags/0.5.0/readme.txt (modified) (2 diffs)
-
tags/0.5.0/src/api.php (modified) (2 diffs)
-
tags/0.5.0/src/utils.php (modified) (6 diffs)
-
trunk/clickpress-migration.php (modified) (2 diffs)
-
trunk/consts.php (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/src/api.php (modified) (2 diffs)
-
trunk/src/utils.php (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
one-click-migration/tags/0.5.0/clickpress-migration.php
r3711253 r3715166 4 4 * Plugin Name: ClickPress Migration 5 5 * Description: Migrate your free website automatically to ClickPress. 6 * Version: 0. 4.16 * Version: 0.5.0 7 7 * Requires at least: 5.6 8 8 * Requires PHP: 7.4 … … 86 86 "lockedPassword" => $_POST["lockedPassword"], 87 87 88 "existsSiteID" => $_POST["existsSiteID"] 88 "existsSiteID" => $_POST["existsSiteID"], 89 90 // 0.5.0+: lets ClickPress choose PUSH mode (this site uploads its 91 // export to ClickPress instead of ClickPress downloading it). Older 92 // plugins send nothing and get pull. 93 "pluginVersion" => CLICKPRESS_MIGRATION_VERSION 89 94 ); 90 95 -
one-click-migration/tags/0.5.0/consts.php
r3506812 r3715166 1 1 <?php 2 2 const ENV = "production"; 3 const CLICKPRESS_MIGRATION_VERSION = "0.5.0"; 3 4 const LOWEST_SUPPORTED_VERSION = "7.4"; 4 5 const HIGHEST_SUPPORTED_VERSION = "8.3"; -
one-click-migration/tags/0.5.0/readme.txt
r3711253 r3715166 3 3 Requires at least: 5.6 4 4 Tested up to: 6.6.1 5 Stable tag: 0. 4.15 Stable tag: 0.5.0 6 6 Requires PHP: 7.4 7 7 License: GPLv2 or later … … 78 78 == Changelog == 79 79 80 = 0.5.0 = 81 * New: "push" migration. Your website sends its export to ClickPress itself, instead of ClickPress downloading it. Hosts that limit or block big downloads no longer stop a migration. ClickPress turns it on; nothing changes for you. 82 * Push keeps files up to 2 GB (was 50 MB). 83 80 84 = 0.4.1 = 81 85 * Fix: the get_last_output recovery step no longer writes its own "no-output-log" answer into last_api_output.log, where the next status check read it as the step's real result and stopped the migration. -
one-click-migration/tags/0.5.0/src/api.php
r3711253 r3715166 63 63 64 64 $output["uid"] = $_POST["uid"] ?? -1; 65 66 // PUSH MODE (0.5.0): ClickPress marks every step of a push migration. The 67 // export then ends a block on timeout instead of rewriting it, keeps files up 68 // to 2 GB, and stores big files unzipped; see utils.php. 69 $clickpress_push_mode = !empty($_POST["push"]); 65 70 66 71 header("Content-Type: application/json"); … … 179 184 } 180 185 186 if ($_POST["step"] === "upload_block") { 187 // PUSH MODE: send one finished block to ClickPress in 20 MB parts, instead 188 // of ClickPress downloading it. 189 clickpress_push_upload_block(); 190 } 191 181 192 if ($_POST["step"] === "get_last_output") { 182 193 $logPath = dirname(plugin_dir_path(__FILE__)) . "/output/last_api_output.log"; -
one-click-migration/tags/0.5.0/src/utils.php
r3548659 r3715166 263 263 } 264 264 265 /** 266 * PUSH MODE (0.5.0): out of time in the middle of a database block. Pull 267 * re-calls export_database on the same block, which rewrites it from byte 0; 268 * push instead ends the block where the writing stopped and uploads it, so 269 * nothing already written is lost. The row/table index already points at the 270 * first thing NOT written, so the next block continues from there. 271 */ 272 function clickpress_push_end_block_on_timeout(&$fileHandle): bool 273 { 274 global $output, $clickpress_push_mode; 275 276 if (empty($clickpress_push_mode)) { 277 return false; 278 } 279 ftruncate($fileHandle, ftell($fileHandle)); 280 fclose($fileHandle); 281 $output["result"] = "chunk_ready"; 282 return true; 283 } 284 285 /** 286 * PUSH MODE (0.5.0): upload one finished block (a .gz or .zip in output/) to 287 * ClickPress, in 20 MB parts named "<name>.partNNNN", starting at `offset`. 288 * Uploads parts until the block is done or the PHP time budget is nearly 289 * used; then answers "timeout" with the offset to continue from. ClickPress 290 * checks every part on its side before it joins them. 291 * 292 * Why: some hosts limit or block big downloads to one IP (Hostinger answered 293 * ClickPress's downloads with 429 after ~1.6 GB). An upload made by the site 294 * itself is not limited that way. 295 */ 296 function clickpress_push_upload_block(): void 297 { 298 global $output; 299 300 $partSize = 20 * 1024 * 1024; 301 $outputDir = realpath(path_join(dirname(plugin_dir_path(__FILE__)), "output")); 302 $blockPath = realpath($_POST["block_path"] ?? ""); 303 $name = $_POST["name"] ?? ""; 304 $siteID = $_POST["site_id"] ?? ""; 305 $offset = (int)($_POST["offset"] ?? 0); 306 307 // Only a block this plugin wrote into its own output folder can be sent. 308 if (!$outputDir || !$blockPath || strpos($blockPath, $outputDir . DIRECTORY_SEPARATOR) !== 0 || !is_file($blockPath)) { 309 $output["message"] = "block-not-found"; 310 return; 311 } 312 if ( 313 !preg_match('/^(db_block_\d{6}\.chunk\.gz|file_block_\d{6}\.chunk\.zip)$/', $name) || 314 !preg_match('/^[0-9a-f]{24}$/', $siteID) || 315 $offset < 0 || $offset % $partSize !== 0 316 ) { 317 $output["message"] = "bad-parameters"; 318 return; 319 } 320 321 $size = filesize($blockPath); 322 $url = (ENV === "production" ? "https://my.click.press/api" : "http://localhost:3001") . "/migration/push/chunk"; 323 324 while ($offset < $size) { 325 // Always send at least one part per call, so every call moves forward. 326 if ($offset > (int)($_POST["offset"] ?? 0) && clickpress_about_to_reach_timeout()) { 327 $output["result"] = "timeout"; 328 $output["offset"] = $offset; 329 return; 330 } 331 332 $fp = fopen($blockPath, "rb"); 333 fseek($fp, $offset); 334 $data = fread($fp, $partSize); 335 fclose($fp); 336 337 $part = sprintf("%s.part%04d", $name, intdiv($offset, $partSize) + 1); 338 $sent = false; 339 $why = ""; 340 for ($try = 1; $try <= 3 && !$sent; $try++) { 341 @set_time_limit(180); 342 $res = wp_remote_post($url . "?siteID=" . rawurlencode($siteID) . "&name=" . rawurlencode($part), array( 343 "timeout" => 120, 344 "headers" => array( 345 "Content-Type" => "application/octet-stream", 346 "x-migration-token" => $_POST["token"] ?? "", 347 ), 348 "body" => $data, 349 )); 350 if (is_wp_error($res)) { 351 $why = "network: " . $res->get_error_message(); 352 } else { 353 $code = (int)wp_remote_retrieve_response_code($res); 354 $body = json_decode(wp_remote_retrieve_body($res), true); 355 if ($code === 200 && is_array($body) && ($body["result"] ?? "") === "success") { 356 $sent = true; 357 break; 358 } 359 $why = "http-{$code}: " . (is_array($body) ? ($body["message"] ?? "") : ""); 360 } 361 if ($try < 3) { 362 sleep(3 * $try); 363 } 364 } 365 if (!$sent) { 366 $output["message"] = "upload-failed {$part}: {$why}"; 367 $output["offset"] = $offset; 368 return; 369 } 370 $offset += strlen($data); 371 } 372 373 $output["result"] = "success"; 374 $output["parts"] = max(1, (int)ceil($size / $partSize)); 375 $output["bytes"] = $size; 376 } 377 265 378 function clickpress_prepare_block_for_write(): void 266 379 { … … 415 528 for (; $output["table_index"] < count($tables); $output["table_index"]++) { 416 529 if (clickpress_about_to_reach_timeout()) { 530 if (clickpress_push_end_block_on_timeout($fileHandle)) { 531 return; 532 } 417 533 fclose($fileHandle); 418 534 $output["result"] = "timeout"; … … 472 588 473 589 if (clickpress_about_to_reach_timeout()) { 590 if (clickpress_push_end_block_on_timeout($fileHandle)) { 591 return; 592 } 474 593 fclose($fileHandle); 475 594 $output["result"] = "timeout"; … … 513 632 function clickpress_migration_list_files_to_transfer() 514 633 { 515 global $output; 634 global $output, $clickpress_push_mode; 635 636 // Pull skips files over 50 MB (ClickPress re-fetched missing media 637 // afterwards). Push has no second pass — it uploads every file in 20 MB 638 // parts, so it keeps files up to 2 GB. 639 $maxFileSize = empty($clickpress_push_mode) ? 50 * pow(1024, 2) : 2 * pow(1024, 3); 516 640 517 641 if (empty($_POST["output_file_path"])) { … … 557 681 is_link($filePath) || 558 682 clickpress_migration_ends_with($filePath, "/wp-content/plugins/one-click-migration") || 559 $fileSize > 50 * pow(1024, 2)||683 $fileSize > $maxFileSize || 560 684 preg_match("/.*\.bkup|.*\.gz|.*\.jpa|.*\.ini|.*\.log|.*\.sql|.*\.tar|.*\.tar.gz|.*\.wpress|.*\.zip|.*\/\.wysiwygPro_.*|.*\/backupbuddy_backups\/.*|.*\/cache\/smarty\/.*|.*\/com_akeeba\/backup\/.*|.*\/core\.[0-9].*|.*\/error_log|.*\/var\/amasty_fpc\/.*|.*\/var\/backups\/.*|.*\/var\/cache\/.*|.*\/var\/debug\/.*|.*\/var\/export\/.*|.*\/var\/import\/.*|.*\/var\/log\/.*|.*\/var\/report\/.*|.*\/var\/session\/.*|.*\/var\/tmp\/.*|.*\/wp-content\/cache\/.*|.*\/wp-content\/wphb-cache\/.*|.*\/wp-content\/uploads\/wpcf7_captcha\/.*|.*\/wp-content\/widget-cache\/.*|.*\/wptsc-cachedir\/.*|^\.MirrorSearch|^\.cpanel\/.*\.sock|^\.trash|^access-logs\/.*|^backup-.*\.tar\.gz|^logs\/.*|^public_ftp\/.*|^public_html\/cache\/.*|^site-.*\.tar\.gz|^softaculous_backups\/.*|^tmp\/.*/", $filePath) 561 685 ) { … … 682 806 } else if (is_file($filePath) === true) { 683 807 $state = $zip->addFile($filePath); 808 // PUSH MODE: a big file (usually a video or an archive, which 809 // barely compresses) is STORED, not deflated, so closing the 810 // zip is a quick copy and fits in one PHP request. 811 if ( 812 $state && !empty($GLOBALS["clickpress_push_mode"]) && 813 $fileSize > 10 * pow(1024, 2) && method_exists($zip, "setCompressionIndex") 814 ) { 815 $zip->setCompressionIndex($zip->numFiles - 1, ZipArchive::CM_STORE); 816 } 684 817 } 685 818 -
one-click-migration/trunk/clickpress-migration.php
r3711253 r3715166 4 4 * Plugin Name: ClickPress Migration 5 5 * Description: Migrate your free website automatically to ClickPress. 6 * Version: 0. 4.16 * Version: 0.5.0 7 7 * Requires at least: 5.6 8 8 * Requires PHP: 7.4 … … 86 86 "lockedPassword" => $_POST["lockedPassword"], 87 87 88 "existsSiteID" => $_POST["existsSiteID"] 88 "existsSiteID" => $_POST["existsSiteID"], 89 90 // 0.5.0+: lets ClickPress choose PUSH mode (this site uploads its 91 // export to ClickPress instead of ClickPress downloading it). Older 92 // plugins send nothing and get pull. 93 "pluginVersion" => CLICKPRESS_MIGRATION_VERSION 89 94 ); 90 95 -
one-click-migration/trunk/consts.php
r3506812 r3715166 1 1 <?php 2 2 const ENV = "production"; 3 const CLICKPRESS_MIGRATION_VERSION = "0.5.0"; 3 4 const LOWEST_SUPPORTED_VERSION = "7.4"; 4 5 const HIGHEST_SUPPORTED_VERSION = "8.3"; -
one-click-migration/trunk/readme.txt
r3711253 r3715166 3 3 Requires at least: 5.6 4 4 Tested up to: 6.6.1 5 Stable tag: 0. 4.15 Stable tag: 0.5.0 6 6 Requires PHP: 7.4 7 7 License: GPLv2 or later … … 78 78 == Changelog == 79 79 80 = 0.5.0 = 81 * New: "push" migration. Your website sends its export to ClickPress itself, instead of ClickPress downloading it. Hosts that limit or block big downloads no longer stop a migration. ClickPress turns it on; nothing changes for you. 82 * Push keeps files up to 2 GB (was 50 MB). 83 80 84 = 0.4.1 = 81 85 * Fix: the get_last_output recovery step no longer writes its own "no-output-log" answer into last_api_output.log, where the next status check read it as the step's real result and stopped the migration. -
one-click-migration/trunk/src/api.php
r3711253 r3715166 63 63 64 64 $output["uid"] = $_POST["uid"] ?? -1; 65 66 // PUSH MODE (0.5.0): ClickPress marks every step of a push migration. The 67 // export then ends a block on timeout instead of rewriting it, keeps files up 68 // to 2 GB, and stores big files unzipped; see utils.php. 69 $clickpress_push_mode = !empty($_POST["push"]); 65 70 66 71 header("Content-Type: application/json"); … … 179 184 } 180 185 186 if ($_POST["step"] === "upload_block") { 187 // PUSH MODE: send one finished block to ClickPress in 20 MB parts, instead 188 // of ClickPress downloading it. 189 clickpress_push_upload_block(); 190 } 191 181 192 if ($_POST["step"] === "get_last_output") { 182 193 $logPath = dirname(plugin_dir_path(__FILE__)) . "/output/last_api_output.log"; -
one-click-migration/trunk/src/utils.php
r3548659 r3715166 263 263 } 264 264 265 /** 266 * PUSH MODE (0.5.0): out of time in the middle of a database block. Pull 267 * re-calls export_database on the same block, which rewrites it from byte 0; 268 * push instead ends the block where the writing stopped and uploads it, so 269 * nothing already written is lost. The row/table index already points at the 270 * first thing NOT written, so the next block continues from there. 271 */ 272 function clickpress_push_end_block_on_timeout(&$fileHandle): bool 273 { 274 global $output, $clickpress_push_mode; 275 276 if (empty($clickpress_push_mode)) { 277 return false; 278 } 279 ftruncate($fileHandle, ftell($fileHandle)); 280 fclose($fileHandle); 281 $output["result"] = "chunk_ready"; 282 return true; 283 } 284 285 /** 286 * PUSH MODE (0.5.0): upload one finished block (a .gz or .zip in output/) to 287 * ClickPress, in 20 MB parts named "<name>.partNNNN", starting at `offset`. 288 * Uploads parts until the block is done or the PHP time budget is nearly 289 * used; then answers "timeout" with the offset to continue from. ClickPress 290 * checks every part on its side before it joins them. 291 * 292 * Why: some hosts limit or block big downloads to one IP (Hostinger answered 293 * ClickPress's downloads with 429 after ~1.6 GB). An upload made by the site 294 * itself is not limited that way. 295 */ 296 function clickpress_push_upload_block(): void 297 { 298 global $output; 299 300 $partSize = 20 * 1024 * 1024; 301 $outputDir = realpath(path_join(dirname(plugin_dir_path(__FILE__)), "output")); 302 $blockPath = realpath($_POST["block_path"] ?? ""); 303 $name = $_POST["name"] ?? ""; 304 $siteID = $_POST["site_id"] ?? ""; 305 $offset = (int)($_POST["offset"] ?? 0); 306 307 // Only a block this plugin wrote into its own output folder can be sent. 308 if (!$outputDir || !$blockPath || strpos($blockPath, $outputDir . DIRECTORY_SEPARATOR) !== 0 || !is_file($blockPath)) { 309 $output["message"] = "block-not-found"; 310 return; 311 } 312 if ( 313 !preg_match('/^(db_block_\d{6}\.chunk\.gz|file_block_\d{6}\.chunk\.zip)$/', $name) || 314 !preg_match('/^[0-9a-f]{24}$/', $siteID) || 315 $offset < 0 || $offset % $partSize !== 0 316 ) { 317 $output["message"] = "bad-parameters"; 318 return; 319 } 320 321 $size = filesize($blockPath); 322 $url = (ENV === "production" ? "https://my.click.press/api" : "http://localhost:3001") . "/migration/push/chunk"; 323 324 while ($offset < $size) { 325 // Always send at least one part per call, so every call moves forward. 326 if ($offset > (int)($_POST["offset"] ?? 0) && clickpress_about_to_reach_timeout()) { 327 $output["result"] = "timeout"; 328 $output["offset"] = $offset; 329 return; 330 } 331 332 $fp = fopen($blockPath, "rb"); 333 fseek($fp, $offset); 334 $data = fread($fp, $partSize); 335 fclose($fp); 336 337 $part = sprintf("%s.part%04d", $name, intdiv($offset, $partSize) + 1); 338 $sent = false; 339 $why = ""; 340 for ($try = 1; $try <= 3 && !$sent; $try++) { 341 @set_time_limit(180); 342 $res = wp_remote_post($url . "?siteID=" . rawurlencode($siteID) . "&name=" . rawurlencode($part), array( 343 "timeout" => 120, 344 "headers" => array( 345 "Content-Type" => "application/octet-stream", 346 "x-migration-token" => $_POST["token"] ?? "", 347 ), 348 "body" => $data, 349 )); 350 if (is_wp_error($res)) { 351 $why = "network: " . $res->get_error_message(); 352 } else { 353 $code = (int)wp_remote_retrieve_response_code($res); 354 $body = json_decode(wp_remote_retrieve_body($res), true); 355 if ($code === 200 && is_array($body) && ($body["result"] ?? "") === "success") { 356 $sent = true; 357 break; 358 } 359 $why = "http-{$code}: " . (is_array($body) ? ($body["message"] ?? "") : ""); 360 } 361 if ($try < 3) { 362 sleep(3 * $try); 363 } 364 } 365 if (!$sent) { 366 $output["message"] = "upload-failed {$part}: {$why}"; 367 $output["offset"] = $offset; 368 return; 369 } 370 $offset += strlen($data); 371 } 372 373 $output["result"] = "success"; 374 $output["parts"] = max(1, (int)ceil($size / $partSize)); 375 $output["bytes"] = $size; 376 } 377 265 378 function clickpress_prepare_block_for_write(): void 266 379 { … … 415 528 for (; $output["table_index"] < count($tables); $output["table_index"]++) { 416 529 if (clickpress_about_to_reach_timeout()) { 530 if (clickpress_push_end_block_on_timeout($fileHandle)) { 531 return; 532 } 417 533 fclose($fileHandle); 418 534 $output["result"] = "timeout"; … … 472 588 473 589 if (clickpress_about_to_reach_timeout()) { 590 if (clickpress_push_end_block_on_timeout($fileHandle)) { 591 return; 592 } 474 593 fclose($fileHandle); 475 594 $output["result"] = "timeout"; … … 513 632 function clickpress_migration_list_files_to_transfer() 514 633 { 515 global $output; 634 global $output, $clickpress_push_mode; 635 636 // Pull skips files over 50 MB (ClickPress re-fetched missing media 637 // afterwards). Push has no second pass — it uploads every file in 20 MB 638 // parts, so it keeps files up to 2 GB. 639 $maxFileSize = empty($clickpress_push_mode) ? 50 * pow(1024, 2) : 2 * pow(1024, 3); 516 640 517 641 if (empty($_POST["output_file_path"])) { … … 557 681 is_link($filePath) || 558 682 clickpress_migration_ends_with($filePath, "/wp-content/plugins/one-click-migration") || 559 $fileSize > 50 * pow(1024, 2)||683 $fileSize > $maxFileSize || 560 684 preg_match("/.*\.bkup|.*\.gz|.*\.jpa|.*\.ini|.*\.log|.*\.sql|.*\.tar|.*\.tar.gz|.*\.wpress|.*\.zip|.*\/\.wysiwygPro_.*|.*\/backupbuddy_backups\/.*|.*\/cache\/smarty\/.*|.*\/com_akeeba\/backup\/.*|.*\/core\.[0-9].*|.*\/error_log|.*\/var\/amasty_fpc\/.*|.*\/var\/backups\/.*|.*\/var\/cache\/.*|.*\/var\/debug\/.*|.*\/var\/export\/.*|.*\/var\/import\/.*|.*\/var\/log\/.*|.*\/var\/report\/.*|.*\/var\/session\/.*|.*\/var\/tmp\/.*|.*\/wp-content\/cache\/.*|.*\/wp-content\/wphb-cache\/.*|.*\/wp-content\/uploads\/wpcf7_captcha\/.*|.*\/wp-content\/widget-cache\/.*|.*\/wptsc-cachedir\/.*|^\.MirrorSearch|^\.cpanel\/.*\.sock|^\.trash|^access-logs\/.*|^backup-.*\.tar\.gz|^logs\/.*|^public_ftp\/.*|^public_html\/cache\/.*|^site-.*\.tar\.gz|^softaculous_backups\/.*|^tmp\/.*/", $filePath) 561 685 ) { … … 682 806 } else if (is_file($filePath) === true) { 683 807 $state = $zip->addFile($filePath); 808 // PUSH MODE: a big file (usually a video or an archive, which 809 // barely compresses) is STORED, not deflated, so closing the 810 // zip is a quick copy and fits in one PHP request. 811 if ( 812 $state && !empty($GLOBALS["clickpress_push_mode"]) && 813 $fileSize > 10 * pow(1024, 2) && method_exists($zip, "setCompressionIndex") 814 ) { 815 $zip->setCompressionIndex($zip->numFiles - 1, ZipArchive::CM_STORE); 816 } 684 817 } 685 818
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)