Plugin Directory

Changeset 3715166


Ignore:
Timestamp:
09/27/2026 08:38:16 AM (4 weeks ago)
Author:
gididreamvps
Message:

0.5.0: push migration - the site uploads its export to ClickPress instead of ClickPress downloading it (hosts that limit big downloads no longer stop a migration); push keeps files up to 2 GB.

Location:
one-click-migration
Files:
10 edited
1 copied

Legend:

Unmodified
Added
Removed
  • one-click-migration/tags/0.5.0/clickpress-migration.php

    r3711253 r3715166  
    44 * Plugin Name: ClickPress Migration
    55 * Description: Migrate your free website automatically to ClickPress.
    6  * Version: 0.4.1
     6 * Version: 0.5.0
    77 * Requires at least: 5.6
    88 * Requires PHP: 7.4
    … …  
    8686        "lockedPassword" => $_POST["lockedPassword"],
    8787
    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
    8994    );
    9095
  • one-click-migration/tags/0.5.0/consts.php

    r3506812 r3715166  
    11<?php
    22const ENV = "production";
     3const CLICKPRESS_MIGRATION_VERSION = "0.5.0";
    34const LOWEST_SUPPORTED_VERSION = "7.4";
    45const HIGHEST_SUPPORTED_VERSION = "8.3";
  • one-click-migration/tags/0.5.0/readme.txt

    r3711253 r3715166  
    33Requires at least: 5.6
    44Tested up to: 6.6.1
    5 Stable tag: 0.4.1
     5Stable tag: 0.5.0
    66Requires PHP: 7.4
    77License: GPLv2 or later
    … …  
    7878== Changelog ==
    7979
     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
    8084= 0.4.1 =
    8185* 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  
    6363
    6464$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"]);
    6570
    6671header("Content-Type: application/json");
    … …  
    179184}
    180185
     186if ($_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
    181192if ($_POST["step"] === "get_last_output") {
    182193    $logPath = dirname(plugin_dir_path(__FILE__)) . "/output/last_api_output.log";
  • one-click-migration/tags/0.5.0/src/utils.php

    r3548659 r3715166  
    263263}
    264264
     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 */
     272function 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 */
     296function 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
    265378function clickpress_prepare_block_for_write(): void
    266379{
    … …  
    415528    for (; $output["table_index"] < count($tables); $output["table_index"]++) {
    416529        if (clickpress_about_to_reach_timeout()) {
     530            if (clickpress_push_end_block_on_timeout($fileHandle)) {
     531                return;
     532            }
    417533            fclose($fileHandle);
    418534            $output["result"] = "timeout";
    … …  
    472588
    473589    if (clickpress_about_to_reach_timeout()) {
     590        if (clickpress_push_end_block_on_timeout($fileHandle)) {
     591            return;
     592        }
    474593        fclose($fileHandle);
    475594        $output["result"] = "timeout";
    … …  
    513632function clickpress_migration_list_files_to_transfer()
    514633{
    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);
    516640
    517641    if (empty($_POST["output_file_path"])) {
    … …  
    557681                is_link($filePath) ||
    558682                clickpress_migration_ends_with($filePath, "/wp-content/plugins/one-click-migration") ||
    559                 $fileSize > 50 * pow(1024, 2) ||
     683                $fileSize > $maxFileSize ||
    560684                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)
    561685            ) {
    … …  
    682806            } else if (is_file($filePath) === true) {
    683807                $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                }
    684817            }
    685818
  • one-click-migration/trunk/clickpress-migration.php

    r3711253 r3715166  
    44 * Plugin Name: ClickPress Migration
    55 * Description: Migrate your free website automatically to ClickPress.
    6  * Version: 0.4.1
     6 * Version: 0.5.0
    77 * Requires at least: 5.6
    88 * Requires PHP: 7.4
    … …  
    8686        "lockedPassword" => $_POST["lockedPassword"],
    8787
    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
    8994    );
    9095
  • one-click-migration/trunk/consts.php

    r3506812 r3715166  
    11<?php
    22const ENV = "production";
     3const CLICKPRESS_MIGRATION_VERSION = "0.5.0";
    34const LOWEST_SUPPORTED_VERSION = "7.4";
    45const HIGHEST_SUPPORTED_VERSION = "8.3";
  • one-click-migration/trunk/readme.txt

    r3711253 r3715166  
    33Requires at least: 5.6
    44Tested up to: 6.6.1
    5 Stable tag: 0.4.1
     5Stable tag: 0.5.0
    66Requires PHP: 7.4
    77License: GPLv2 or later
    … …  
    7878== Changelog ==
    7979
     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
    8084= 0.4.1 =
    8185* 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  
    6363
    6464$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"]);
    6570
    6671header("Content-Type: application/json");
    … …  
    179184}
    180185
     186if ($_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
    181192if ($_POST["step"] === "get_last_output") {
    182193    $logPath = dirname(plugin_dir_path(__FILE__)) . "/output/last_api_output.log";
  • one-click-migration/trunk/src/utils.php

    r3548659 r3715166  
    263263}
    264264
     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 */
     272function 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 */
     296function 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
    265378function clickpress_prepare_block_for_write(): void
    266379{
    … …  
    415528    for (; $output["table_index"] < count($tables); $output["table_index"]++) {
    416529        if (clickpress_about_to_reach_timeout()) {
     530            if (clickpress_push_end_block_on_timeout($fileHandle)) {
     531                return;
     532            }
    417533            fclose($fileHandle);
    418534            $output["result"] = "timeout";
    … …  
    472588
    473589    if (clickpress_about_to_reach_timeout()) {
     590        if (clickpress_push_end_block_on_timeout($fileHandle)) {
     591            return;
     592        }
    474593        fclose($fileHandle);
    475594        $output["result"] = "timeout";
    … …  
    513632function clickpress_migration_list_files_to_transfer()
    514633{
    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);
    516640
    517641    if (empty($_POST["output_file_path"])) {
    … …  
    557681                is_link($filePath) ||
    558682                clickpress_migration_ends_with($filePath, "/wp-content/plugins/one-click-migration") ||
    559                 $fileSize > 50 * pow(1024, 2) ||
     683                $fileSize > $maxFileSize ||
    560684                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)
    561685            ) {
    … …  
    682806            } else if (is_file($filePath) === true) {
    683807                $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                }
    684817            }
    685818
Note: See TracChangeset for help on using the changeset viewer.