Changeset 3440991
- Timestamp:
- 01/16/2026 12:55:46 PM (2 months ago)
- Location:
- surflink
- Files:
-
- 305 added
- 10 edited
-
tags/2.3.9 (added)
-
tags/2.3.9/assets (added)
-
tags/2.3.9/assets/css (added)
-
tags/2.3.9/assets/css/surfl-loginhider.css (added)
-
tags/2.3.9/assets/css/surfl.css (added)
-
tags/2.3.9/assets/fast-forward.php (added)
-
tags/2.3.9/assets/icon_logo_sm_20.png (added)
-
tags/2.3.9/assets/import_410_sample.csv (added)
-
tags/2.3.9/assets/import_redirect_sample.csv (added)
-
tags/2.3.9/assets/js (added)
-
tags/2.3.9/assets/js/redirects.js (added)
-
tags/2.3.9/assets/js/setting-scripts.js (added)
-
tags/2.3.9/assets/js/surfl-loginhider.js (added)
-
tags/2.3.9/assets/js/surfl.js (added)
-
tags/2.3.9/assets/surflink_white.png (added)
-
tags/2.3.9/includes (added)
-
tags/2.3.9/includes/class-filesystem-helper.php (added)
-
tags/2.3.9/includes/class-log-cleaner.php (added)
-
tags/2.3.9/includes/class-surfl-404.php (added)
-
tags/2.3.9/includes/class-surfl-410.php (added)
-
tags/2.3.9/includes/class-surfl-backup-cleanup.php (added)
-
tags/2.3.9/includes/class-surfl-backup-helper.php (added)
-
tags/2.3.9/includes/class-surfl-backup-settings.php (added)
-
tags/2.3.9/includes/class-surfl-br-loader.php (added)
-
tags/2.3.9/includes/class-surfl-br-replace-engine.php (added)
-
tags/2.3.9/includes/class-surfl-fast-sr.php (added)
-
tags/2.3.9/includes/class-surfl-loader.php (added)
-
tags/2.3.9/includes/class-surfl-loginhider.php (added)
-
tags/2.3.9/includes/class-surfl-module-manager.php (added)
-
tags/2.3.9/includes/class-surfl-plugin-activation.php (added)
-
tags/2.3.9/includes/class-surfl-redirect.php (added)
-
tags/2.3.9/includes/class-surfl-restore-db.php (added)
-
tags/2.3.9/includes/class-surfl-restore-files.php (added)
-
tags/2.3.9/includes/test.php (added)
-
tags/2.3.9/includes/uninstall.php (added)
-
tags/2.3.9/index.php (added)
-
tags/2.3.9/readme.txt (added)
-
tags/2.3.9/surf-link.php (added)
-
tags/2.3.9/templates (added)
-
tags/2.3.9/templates/login-template.php (added)
-
tags/2.3.9/templates/question-tooltip.php (added)
-
tags/2.3.9/templates/surfl-404.php (added)
-
tags/2.3.9/templates/surfl-410-list.php (added)
-
tags/2.3.9/templates/surfl-410.php (added)
-
tags/2.3.9/templates/surfl-autolink-options.php (added)
-
tags/2.3.9/templates/surfl-backup-modals.php (added)
-
tags/2.3.9/templates/surfl-backup-options.php (added)
-
tags/2.3.9/templates/surfl-backup-table.php (added)
-
tags/2.3.9/templates/surfl-backup-warnings.php (added)
-
tags/2.3.9/templates/surfl-backup.php (added)
-
tags/2.3.9/templates/surfl-footer.php (added)
-
tags/2.3.9/templates/surfl-hard-unlink-report.php (added)
-
tags/2.3.9/templates/surfl-hard-unlink.php (added)
-
tags/2.3.9/templates/surfl-hardlink-history.php (added)
-
tags/2.3.9/templates/surfl-hardlink-report.php (added)
-
tags/2.3.9/templates/surfl-hardlink.php (added)
-
tags/2.3.9/templates/surfl-loginhider-failed-attempts.php (added)
-
tags/2.3.9/templates/surfl-loginhider-setting.php (added)
-
tags/2.3.9/templates/surfl-post-title-replace.php (added)
-
tags/2.3.9/templates/surfl-primary-nav.php (added)
-
tags/2.3.9/templates/surfl-pro-ad.php (added)
-
tags/2.3.9/templates/surfl-redirect-html.php (added)
-
tags/2.3.9/templates/surfl-redirect-list-html.php (added)
-
tags/2.3.9/templates/surfl-redirection-rules.php (added)
-
tags/2.3.9/templates/surfl-restore-backup-html.php (added)
-
tags/2.3.9/templates/surfl-restore-status.php (added)
-
tags/2.3.9/templates/surfl-restore-upload-status.php (added)
-
tags/2.3.9/templates/surfl-rules-info-modal.php (added)
-
tags/2.3.9/templates/surfl-saved-autolinks.php (added)
-
tags/2.3.9/templates/surfl-shortlink-form-html.php (added)
-
tags/2.3.9/templates/surfl-shortlink-list-html.php (added)
-
tags/2.3.9/templates/surfl-shortlink-options.php (added)
-
tags/2.3.9/templates/surfl-softlink.php (added)
-
tags/2.3.9/templates/surfl-sr-html.php (added)
-
tags/2.3.9/templates/surfl-sr-report.php (added)
-
tags/2.3.9/templates/surfl-srh.php (added)
-
tags/2.3.9/templates/surfl-text-tooltip.php (added)
-
tags/2.3.9/templates/surfl-url-replace-html.php (added)
-
tags/2.3.9/vendor (added)
-
tags/2.3.9/vendor/freemius (added)
-
tags/2.3.9/vendor/freemius/LICENSE.txt (added)
-
tags/2.3.9/vendor/freemius/assets (added)
-
tags/2.3.9/vendor/freemius/assets/css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/account.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/add-ons.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/affiliation.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/checkout.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/clone-resolution.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/common.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/connect.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/debug.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/dialog-boxes.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/gdpr-optin-notice.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/index.php (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/optout.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/admin/plugins.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/customizer.css (added)
-
tags/2.3.9/vendor/freemius/assets/css/index.php (added)
-
tags/2.3.9/vendor/freemius/assets/img (added)
-
tags/2.3.9/vendor/freemius/assets/img/index.php (added)
-
tags/2.3.9/vendor/freemius/assets/img/plugin-icon.png (added)
-
tags/2.3.9/vendor/freemius/assets/img/slt-surflink.png (added)
-
tags/2.3.9/vendor/freemius/assets/img/surf-link.png (added)
-
tags/2.3.9/vendor/freemius/assets/img/surflink.png (added)
-
tags/2.3.9/vendor/freemius/assets/img/theme-icon.png (added)
-
tags/2.3.9/vendor/freemius/assets/index.php (added)
-
tags/2.3.9/vendor/freemius/assets/js (added)
-
tags/2.3.9/vendor/freemius/assets/js/index.php (added)
-
tags/2.3.9/vendor/freemius/assets/js/jquery.form.js (added)
-
tags/2.3.9/vendor/freemius/assets/js/nojquery.ba-postmessage.js (added)
-
tags/2.3.9/vendor/freemius/assets/js/postmessage.js (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/14fb1bd5b7c41648488b06147f50a0dc.svg (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/178afa6030e76635dbe835e111d2c507.png (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/27b5a722a5553d9de0170325267fccec.png (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/4375c4a3ddc6f637c2ab9a2d7220f91e.png (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/45da596e2b512ffc3bb638baaf0fdc4e.png (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/a34e046aee1702a5690679750a7f4d0f.svg (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/b09d0b38b627c2fa564d050f79f2f064.svg (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/c03f665db27af43971565560adfba594.png (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/cb5fc4f6ec7ada72e986f6e7dde365bf.png (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/d65812c447b4523b42d59018e1c0bb53.png (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/f3aac72a8e63997d6bb888f816457e9b.png (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/fde48e4609a6ddc11d639fc2421f2afd.png (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/freemius-pricing.js (added)
-
tags/2.3.9/vendor/freemius/assets/js/pricing/freemius-pricing.js.LICENSE.txt (added)
-
tags/2.3.9/vendor/freemius/config.php (added)
-
tags/2.3.9/vendor/freemius/includes (added)
-
tags/2.3.9/vendor/freemius/includes/class-freemius-abstract.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-freemius.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-admin-notices.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-api.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-garbage-collector.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-hook-snapshot.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-lock.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-logger.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-options.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-plugin-updater.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-security.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-storage.php (added)
-
tags/2.3.9/vendor/freemius/includes/class-fs-user-lock.php (added)
-
tags/2.3.9/vendor/freemius/includes/customizer (added)
-
tags/2.3.9/vendor/freemius/includes/customizer/class-fs-customizer-support-section.php (added)
-
tags/2.3.9/vendor/freemius/includes/customizer/class-fs-customizer-upsell-control.php (added)
-
tags/2.3.9/vendor/freemius/includes/customizer/index.php (added)
-
tags/2.3.9/vendor/freemius/includes/debug (added)
-
tags/2.3.9/vendor/freemius/includes/debug/class-fs-debug-bar-panel.php (added)
-
tags/2.3.9/vendor/freemius/includes/debug/debug-bar-start.php (added)
-
tags/2.3.9/vendor/freemius/includes/debug/index.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-affiliate-terms.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-affiliate.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-billing.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-entity.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-payment.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-plugin-info.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-plugin-license.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-plugin-plan.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-plugin-tag.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-plugin.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-pricing.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-scope-entity.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-site.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-subscription.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/class-fs-user.php (added)
-
tags/2.3.9/vendor/freemius/includes/entities/index.php (added)
-
tags/2.3.9/vendor/freemius/includes/fs-core-functions.php (added)
-
tags/2.3.9/vendor/freemius/includes/fs-essential-functions.php (added)
-
tags/2.3.9/vendor/freemius/includes/fs-html-escaping-functions.php (added)
-
tags/2.3.9/vendor/freemius/includes/fs-plugin-info-dialog.php (added)
-
tags/2.3.9/vendor/freemius/includes/index.php (added)
-
tags/2.3.9/vendor/freemius/includes/l10n.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-admin-menu-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-admin-notice-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-cache-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-checkout-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-clone-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-contact-form-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-debug-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-gdpr-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-key-value-storage.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-license-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-option-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-permission-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-plan-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/class-fs-plugin-manager.php (added)
-
tags/2.3.9/vendor/freemius/includes/managers/index.php (added)
-
tags/2.3.9/vendor/freemius/includes/sdk (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/Exceptions (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/Exceptions/ArgumentNotExistException.php (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/Exceptions/EmptyArgumentException.php (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/Exceptions/Exception.php (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/Exceptions/InvalidArgumentException.php (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/Exceptions/OAuthException.php (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/Exceptions/index.php (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/FreemiusBase.php (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/FreemiusWordPress.php (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/LICENSE.txt (added)
-
tags/2.3.9/vendor/freemius/includes/sdk/index.php (added)
-
tags/2.3.9/vendor/freemius/includes/supplements (added)
-
tags/2.3.9/vendor/freemius/includes/supplements/fs-essential-functions-1.1.7.1.php (added)
-
tags/2.3.9/vendor/freemius/includes/supplements/fs-essential-functions-2.2.1.php (added)
-
tags/2.3.9/vendor/freemius/includes/supplements/fs-migration-2.5.1.php (added)
-
tags/2.3.9/vendor/freemius/includes/supplements/index.php (added)
-
tags/2.3.9/vendor/freemius/index.php (added)
-
tags/2.3.9/vendor/freemius/languages (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-cs_CZ.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-da_DK.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-de_DE.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-es_ES.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-fr_FR.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-he_IL.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-hu_HU.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-it_IT.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-ja.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-nl_NL.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-ru_RU.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-ta.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius-zh_CN.mo (added)
-
tags/2.3.9/vendor/freemius/languages/freemius.pot (added)
-
tags/2.3.9/vendor/freemius/languages/index.php (added)
-
tags/2.3.9/vendor/freemius/require.php (added)
-
tags/2.3.9/vendor/freemius/start.php (added)
-
tags/2.3.9/vendor/freemius/templates (added)
-
tags/2.3.9/vendor/freemius/templates/account (added)
-
tags/2.3.9/vendor/freemius/templates/account.php (added)
-
tags/2.3.9/vendor/freemius/templates/account/billing.php (added)
-
tags/2.3.9/vendor/freemius/templates/account/index.php (added)
-
tags/2.3.9/vendor/freemius/templates/account/partials (added)
-
tags/2.3.9/vendor/freemius/templates/account/partials/activate-license-button.php (added)
-
tags/2.3.9/vendor/freemius/templates/account/partials/addon.php (added)
-
tags/2.3.9/vendor/freemius/templates/account/partials/deactivate-license-button.php (added)
-
tags/2.3.9/vendor/freemius/templates/account/partials/disconnect-button.php (added)
-
tags/2.3.9/vendor/freemius/templates/account/partials/index.php (added)
-
tags/2.3.9/vendor/freemius/templates/account/partials/site.php (added)
-
tags/2.3.9/vendor/freemius/templates/account/payments.php (added)
-
tags/2.3.9/vendor/freemius/templates/add-ons.php (added)
-
tags/2.3.9/vendor/freemius/templates/add-trial-to-pricing.php (added)
-
tags/2.3.9/vendor/freemius/templates/admin-notice.php (added)
-
tags/2.3.9/vendor/freemius/templates/ajax-loader.php (added)
-
tags/2.3.9/vendor/freemius/templates/api-connectivity-message-js.php (added)
-
tags/2.3.9/vendor/freemius/templates/auto-installation.php (added)
-
tags/2.3.9/vendor/freemius/templates/checkout (added)
-
tags/2.3.9/vendor/freemius/templates/checkout.php (added)
-
tags/2.3.9/vendor/freemius/templates/checkout/frame.php (added)
-
tags/2.3.9/vendor/freemius/templates/checkout/process-redirect.php (added)
-
tags/2.3.9/vendor/freemius/templates/checkout/redirect.php (added)
-
tags/2.3.9/vendor/freemius/templates/clone-resolution-js.php (added)
-
tags/2.3.9/vendor/freemius/templates/connect (added)
-
tags/2.3.9/vendor/freemius/templates/connect.php (added)
-
tags/2.3.9/vendor/freemius/templates/connect/index.php (added)
-
tags/2.3.9/vendor/freemius/templates/connect/permission.php (added)
-
tags/2.3.9/vendor/freemius/templates/connect/permissions-group.php (added)
-
tags/2.3.9/vendor/freemius/templates/contact.php (added)
-
tags/2.3.9/vendor/freemius/templates/debug (added)
-
tags/2.3.9/vendor/freemius/templates/debug.php (added)
-
tags/2.3.9/vendor/freemius/templates/debug/api-calls.php (added)
-
tags/2.3.9/vendor/freemius/templates/debug/index.php (added)
-
tags/2.3.9/vendor/freemius/templates/debug/logger.php (added)
-
tags/2.3.9/vendor/freemius/templates/debug/plugins-themes-sync.php (added)
-
tags/2.3.9/vendor/freemius/templates/debug/scheduled-crons.php (added)
-
tags/2.3.9/vendor/freemius/templates/email.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms (added)
-
tags/2.3.9/vendor/freemius/templates/forms/affiliation.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/data-debug-mode.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/deactivation (added)
-
tags/2.3.9/vendor/freemius/templates/forms/deactivation/contact.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/deactivation/form.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/deactivation/index.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/deactivation/retry-skip.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/email-address-update.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/index.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/license-activation.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/optout.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/premium-versions-upgrade-handler.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/premium-versions-upgrade-metadata.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/resend-key.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/subscription-cancellation.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/trial-start.php (added)
-
tags/2.3.9/vendor/freemius/templates/forms/user-change.php (added)
-
tags/2.3.9/vendor/freemius/templates/gdpr-optin-js.php (added)
-
tags/2.3.9/vendor/freemius/templates/index.php (added)
-
tags/2.3.9/vendor/freemius/templates/js (added)
-
tags/2.3.9/vendor/freemius/templates/js/index.php (added)
-
tags/2.3.9/vendor/freemius/templates/js/jquery.content-change.php (added)
-
tags/2.3.9/vendor/freemius/templates/js/open-license-activation.php (added)
-
tags/2.3.9/vendor/freemius/templates/js/permissions.php (added)
-
tags/2.3.9/vendor/freemius/templates/js/style-premium-theme.php (added)
-
tags/2.3.9/vendor/freemius/templates/partials (added)
-
tags/2.3.9/vendor/freemius/templates/partials/index.php (added)
-
tags/2.3.9/vendor/freemius/templates/partials/network-activation.php (added)
-
tags/2.3.9/vendor/freemius/templates/plugin-icon.php (added)
-
tags/2.3.9/vendor/freemius/templates/plugin-info (added)
-
tags/2.3.9/vendor/freemius/templates/plugin-info/description.php (added)
-
tags/2.3.9/vendor/freemius/templates/plugin-info/features.php (added)
-
tags/2.3.9/vendor/freemius/templates/plugin-info/index.php (added)
-
tags/2.3.9/vendor/freemius/templates/plugin-info/screenshots.php (added)
-
tags/2.3.9/vendor/freemius/templates/pricing.php (added)
-
tags/2.3.9/vendor/freemius/templates/secure-https-header.php (added)
-
tags/2.3.9/vendor/freemius/templates/sticky-admin-notice-js.php (added)
-
tags/2.3.9/vendor/freemius/templates/tabs-capture-js.php (added)
-
tags/2.3.9/vendor/freemius/templates/tabs.php (added)
-
trunk/assets/css/surfl-loginhider.css (modified) (8 diffs)
-
trunk/assets/js/surfl.js (modified) (9 diffs)
-
trunk/includes/class-surfl-backup-helper.php (modified) (25 diffs)
-
trunk/includes/class-surfl-br-loader.php (modified) (9 diffs)
-
trunk/includes/class-surfl-br-replace-engine.php (added)
-
trunk/includes/class-surfl-loginhider.php (modified) (1 diff)
-
trunk/includes/class-surfl-restore-db.php (modified) (4 diffs)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/surf-link.php (modified) (3 diffs)
-
trunk/templates/login-template.php (modified) (1 diff)
-
trunk/templates/surfl-restore-backup-html.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
surflink/trunk/assets/css/surfl-loginhider.css
r3437024 r3440991 1 1 /* CSS for the login form styling */ 2 2 .surfl-lh-login-form input[type="submit"] { 3 background: #172124;3 background: #172124; 4 4 color: white; 5 5 border: transparent; … … 13 13 14 14 .surfl-lh-login-form input[type="submit"]:hover { 15 transform: translateY(-1px);16 transition: 0.3s;15 transform: translateY(-1px); 16 transition: 0.3s; 17 17 } 18 19 18 20 19 .surfl-lh-login-form input[type="text"], 21 20 .surfl-lh-login-form input[type="password"] { 22 border: 1px solid transparent !important;21 border: 1px solid transparent !important; 23 22 background: #42414d; 24 23 box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); 25 24 } 26 25 27 .surfl-lh-login-form label ,.surfl-lh-login-form h2 { 28 color: #c8c8c8; 26 .surfl-lh-login-form label, 27 .surfl-lh-login-form h2 { 28 color: #c8c8c8; 29 29 } 30 30 … … 37 37 /* Full-screen modal overlay */ 38 38 .surfl-lh-modal-overlay { 39 position: fixed;40 top: 0;41 left: 0;42 width: 100%;43 height: 100%;44 background-color: rgba(0, 0, 0, 0.88); /* Dark overlay */45 backdrop-filter: blur(5px); /* Add blur effect */46 display: flex;47 justify-content: center;48 align-items: center;49 z-index: 9999; /* Ensure it's on top of other content */39 position: fixed; 40 top: 0; 41 left: 0; 42 width: 100%; 43 height: 100%; 44 background-color: rgba(0, 0, 0, 0.88); /* Dark overlay */ 45 backdrop-filter: blur(5px); /* Add blur effect */ 46 display: flex; 47 justify-content: center; 48 align-items: center; 49 z-index: 9999; /* Ensure it's on top of other content */ 50 50 } 51 51 52 52 /* Additional styling for the login form container */ 53 53 .surfl-lh-login-form { 54 width: 338px;54 width: 338px; 55 55 padding: 30px; 56 56 border-radius: 8px; 57 57 58 58 margin: 0; 59 background: #2 B2A33;59 background: #2b2a33; 60 60 border: 1px solid transparent; 61 61 } … … 63 63 /* Styling for error messages */ 64 64 .surfl-lh-login-error { 65 margin-bottom: 15px;65 margin-bottom: 15px; 66 66 padding: 10px; 67 67 background-color: #454444; … … 74 74 /* Styling for form elements */ 75 75 76 77 76 .surfl-lh-login-form label { 78 display: block;79 margin-bottom: 5px;80 font-size: 16px;77 display: block; 78 margin-bottom: 5px; 79 font-size: 16px; 81 80 } 82 81 … … 84 83 text-align: center; 85 84 margin-bottom: 30px; 86 font-size: 19px; 87 font-weight: 600; 88 85 font-size: 19px; 86 font-weight: 600; 89 87 } 90 88 91 89 .surfl-lh-login-form input[type="text"], 92 90 .surfl-lh-login-form input[type="password"] { 93 width: 100%;94 padding: 8px;95 box-sizing: border-box;96 border-radius: 4px;91 width: 100%; 92 padding: 8px; 93 box-sizing: border-box; 94 border-radius: 4px; 97 95 } 98 96 99 97 .surfl-lh-login-form .submit { 100 margin-bottom: 0;98 margin-bottom: 0; 101 99 } 102 100 103 101 .surfl-lh-login-form .surfl-lh-login-form input[type="submit"] { 104 width: 100%;102 width: 100%; 105 103 } 106 104 107 105 .surfl-lh-login-form .powered-by { 108 text-align: center;109 margin-top: 20px;110 font-size: 16px;111 color: #888;106 text-align: center; 107 margin-top: 20px; 108 font-size: 16px; 109 color: #888; 112 110 } 113 111 .surfl-lh-forgot-password { … … 116 114 } 117 115 118 .surfl-lh-forgot-password a {119 text-decoration: none;116 .surfl-lh-forgot-password a { 117 text-decoration: none; 120 118 } 121 119 .surfl-gradient-text { 122 background: linear-gradient( 123 to right, 124 #22d3ee, 125 #3b82f6 126 ); 120 background: linear-gradient(to right, #22d3ee, #3b82f6); 127 121 -webkit-background-clip: text; 128 122 -webkit-text-fill-color: transparent; … … 132 126 } 133 127 128 /* LIGHT MODE */ 134 129 130 @media (prefers-color-scheme: light) { 131 .surfl-lh-login-form { 132 background: linear-gradient(to bottom, #cef4fa, #ffffff); 133 } 134 135 .surfl-lh-login-form input[type="submit"] { 136 color: #172124; 137 background-color: white; 138 } 139 140 .surfl-lh-login-form input[type="text"], 141 .surfl-lh-login-form input[type="password"] { 142 background: #fff !important; 143 box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15) !important; 144 } 145 .surfl-gradient-text { 146 background: linear-gradient(to right, #121c1d, #080a90); 147 -webkit-background-clip: text; 148 -webkit-text-fill-color: transparent; 149 150 background-clip: text; 151 color: transparent; 152 } 153 154 .surfl-lh-login-form .powered-by, 155 .surfl-lh-forgot-password , 156 .surfl-lh-login-form label, 157 .surfl-lh-login-form h2 { 158 color: rgb(27, 26, 26); 159 } 160 161 } -
surflink/trunk/assets/js/surfl.js
r3432780 r3440991 88 88 switch (typeName) { 89 89 case "database": 90 msg = message || (status == "ongoing" ? "processing" : msg);90 msg = message || (status == "ongoing" || status == "replace_ongoing" ? "processing" : msg); 91 91 icon = statusDivs.database.find(".dashicons"); 92 92 break; … … 139 139 statusType = statusDivs[typeName]; 140 140 } 141 if (status == "ongoing" ) {141 if (status == "ongoing" || status == "replace_ongoing") { 142 142 icon.removeClass("dashicons-yes dashicons-warning"); 143 143 … … 219 219 }; 220 220 })(jQuery); // pass jQuery as $ 221 221 222 222 223 /* … … 1906 1907 success: function (response) { 1907 1908 if (response.success) { 1908 if (response.data?.status === "ongoing" ) {1909 if (response.data?.status === "ongoing" || response.data?.status === "replace_ongoing") { 1909 1910 showRestoreSuccess( 1910 1911 response.data?.type, … … 1913 1914 ); 1914 1915 1915 restoreNextFile(response.data?.state); 1916 if(response.data?.status === "replace_ongoing"){ 1917 databaseReplaceOperation(response.data?.state); 1918 } 1919 else restoreNextFile(response.data?.state); 1916 1920 } else { 1917 1921 showNotification( … … 1956 1960 }); 1957 1961 } 1962 function databaseReplaceOperation(state = {}) { 1963 1964 1965 const file = filesToRestore[currentFileIndex]; 1966 const fileName = file.filename; 1967 1968 $.ajax({ 1969 url: surflJqObj.ajaxurl, 1970 type: "POST", 1971 data: { 1972 action: "surfl_run_db_replace", 1973 nonce: surflJqObj.nonce, 1974 filename: file.filename, 1975 filepath: file.path, 1976 files_to_backup: JSON.stringify(files_to_backup), 1977 is_last_uploaded_file: 0, 1978 state: JSON.stringify(state), 1979 }, 1980 success: function (response) { 1981 if (response.success) { 1982 if (response.data?.status === "replace_ongoing") { 1983 showRestoreSuccess( 1984 response.data?.type, 1985 response.data?.status, 1986 response.data?.message 1987 ); 1988 1989 databaseReplaceOperation(response.data?.state); 1990 } else { 1991 showNotification( 1992 "success", 1993 `${fileName} restored successfully.`, 1994 "#surfl-restore-modal-msg" 1995 ); 1996 showRestoreSuccess(response.data?.type); 1997 currentFileIndex++; 1998 restoreNextFile(); 1999 } 2000 } else { 2001 failed_backup.push(fileName); 2002 fail_count++; 2003 showNotification( 2004 "error", 2005 `Failed to restore ${fileName}: ${ 2006 (response.data?.message || "Unknown error.", 2007 "#surfl-restore-modal-msg") 2008 }` 2009 ); 2010 showRestoreSuccess( 2011 response.data?.type, 2012 "error", 2013 response.data?.message || "Unknown error." 2014 ); 2015 currentFileIndex++; 2016 restoreNextFile(); 2017 } 2018 }, 2019 error: function (jqXHR, textStatus, errorThrown) { 2020 failed_backup.push(fileName); 2021 fail_count++; 2022 showNotification( 2023 "error", 2024 `An unexpected error occurred while replacing url in ${fileName}. Error: ${textStatus} - ${errorThrown}`, 2025 "#surfl-restore-modal-msg" 2026 ); 2027 currentFileIndex++; 2028 restoreNextFile(); 2029 }, 2030 }); 2031 } 1958 2032 1959 2033 restoreNextFile(); … … 2210 2284 const totalFiles = filesToRestore.length; 2211 2285 2286 function databaseReplaceOperation(state = {}) { 2287 2288 const file = filesToRestore[currentFileIndex]; 2289 const fileName = file.filename; 2290 let is_last_uploaded_file = 2291 totalFiles - 1 == currentFileIndex ? 1 : 0; 2292 2293 $.ajax({ 2294 url: surflJqObj.ajaxurl, 2295 type: "POST", 2296 data: { 2297 action: "surfl_run_db_replace", 2298 nonce: surflJqObj.nonce, 2299 filename: file.filename, 2300 filepath: file.path, 2301 files_to_backup: JSON.stringify(files_to_backup), 2302 is_last_uploaded_file: is_last_uploaded_file, 2303 state: JSON.stringify(state), 2304 }, 2305 success: function (response) { 2306 if (response.success) { 2307 if (response.data?.status === "replace_ongoing") { 2308 showUploadRestoreSuccess( 2309 response.data?.type, 2310 response.data?.status, 2311 response.data?.message 2312 ); 2313 2314 databaseReplaceOperation(response.data?.state); 2315 } else { 2316 showNotification( 2317 "success", 2318 `${fileName} restored successfully.`, 2319 "#surfl-upload-restore-msg" 2320 ); 2321 showUploadRestoreSuccess(response.data?.type); 2322 2323 currentFileIndex++; 2324 restoreNextFile(); 2325 } 2326 } else { 2327 failed_backup.push(fileName); 2328 fail_count++; 2329 showNotification( 2330 "error", 2331 `Failed to restore ${fileName}: ${ 2332 (response.data?.message || "Unknown error.", 2333 "#surfl-upload-restore-msg") 2334 }` 2335 ); 2336 2337 showUploadRestoreSuccess( 2338 response.data?.type, 2339 "error", 2340 response.data?.message || "Unknown error." 2341 ); 2342 currentFileIndex++; 2343 restoreNextFile(); 2344 } 2345 }, 2346 error: function (jqXHR, textStatus, errorThrown) { 2347 failed_backup.push(fileName); 2348 fail_count++; 2349 showNotification( 2350 "error", 2351 `An unexpected error occurred while replacing url in ${fileName}. Error: ${textStatus} - ${errorThrown}`, 2352 "#surfl-upload-restore-msg" 2353 ); 2354 currentFileIndex++; 2355 restoreNextFile(); 2356 }, 2357 }); 2358 } 2212 2359 function restoreNextFile(state = {}) { 2213 2360 if (currentFileIndex >= totalFiles) { … … 2281 2428 success: function (response) { 2282 2429 if (response.success) { 2283 if (response.data?.status === "ongoing") { 2284 showUploadRestoreSuccess( 2285 response.data?.type, 2286 response.data?.status, 2287 response.data?.message 2288 ); 2289 2290 restoreNextFile(response.data?.state); 2291 } else { 2430 if (response.data?.status === "ongoing" || response.data?.status === "replace_ongoing") { 2431 showUploadRestoreSuccess( 2432 response.data?.type, 2433 response.data?.status, 2434 response.data?.message 2435 ); 2436 2437 if(response.data?.status === "replace_ongoing"){ 2438 databaseReplaceOperation(response.data?.state); 2439 } 2440 else restoreNextFile(response.data?.state); 2441 } else { 2292 2442 showNotification( 2293 2443 "success", … … 2333 2483 }); 2334 2484 } 2335 2336 2485 restoreNextFile(); 2337 2486 } else { -
surflink/trunk/includes/class-surfl-backup-helper.php
r3437018 r3440991 13 13 public $subdir; 14 14 public $errors = []; 15 public $db_prefix; 16 public $placeholder = '{temp_prefix_surflink}'; 17 15 18 16 19 public function __construct() 17 20 { 21 global $wpdb; 22 $this->db_prefix = $wpdb->prefix; 18 23 $this->start_time = time(); 19 24 $this->set_optimal_settings(); … … 158 163 $sql_file = $backup_subdir . '/database.sql'; 159 164 $zip_file = $backup_subdir . '/database.zip'; 165 $json_file = $backup_subdir . '/db-info.json'; 160 166 $temp_file = null; 161 167 … … 171 177 $batch_size = $this->calculate_initial_batch_size($avg_row_length); 172 178 $processed_table = null; 173 // $batch_size = 1000;179 // $batch_size = 1000; 174 180 175 181 … … 231 237 fclose($fp); // Close after writing header, will reopen in append mode 232 238 233 239 $db_info = [ 240 'operator' => 'SurfLink', 241 'site_url' => SURFL_SITE_URL, 242 'home_url' => SURFL_HOME_URL, 243 'table_prefix' => $wpdb->prefix, 244 // Check if your plugin defines a specific version constant, e.g. SURFLINK_VERSION 245 'plugin_version' => SURFL_VERSION 246 ]; 247 248 // Write to subdir 249 if (file_put_contents($json_file, json_encode($db_info, JSON_PRETTY_PRINT)) === false) { 250 throw new Exception('Failed to create db-info.json'); 251 } 234 252 $state = [ 235 253 'done' => false, … … 338 356 339 357 // Create zip archive 340 if ($this->create_zip_archive($sql_file, $zip_file )) {358 if ($this->create_zip_archive($sql_file, $zip_file, $json_file)) { 341 359 // Verify backup integrity 342 360 if ($this->verify_backup($zip_file)) { … … 446 464 447 465 fwrite($fp, "\n--\n-- Stored Procedures\n--\n\n"); 466 467 $prefix_quoted = preg_quote($this->db_prefix, '/'); 448 468 foreach ($procedures as $proc) { 449 469 $procedure_name = $proc->SPECIFIC_NAME; … … 454 474 } 455 475 456 // 🔹Remove DEFINER clause476 // 1. Remove DEFINER clause 457 477 $clean_sql = preg_replace('/DEFINER=`[^`]+`@`[^`]+`\s*/', '', $create_proc[2]); 478 479 // 2. Dynamicize Table Prefix 480 481 // Replace `prefix with `placeholder globally 482 $clean_sql = preg_replace("/`{$prefix_quoted}/", "`{$this->placeholder}", $clean_sql); 458 483 459 484 $output = "/*!50003 DROP PROCEDURE IF EXISTS `$procedure_name` */;\n"; … … 489 514 490 515 fwrite($fp, "\n--\n-- Triggers\n--\n\n"); 516 517 $prefix_quoted = preg_quote($this->db_prefix, '/'); 491 518 foreach ($triggers as $trigger) { 492 519 $trigger_name = $trigger->TRIGGER_NAME; … … 500 527 $clean_sql = preg_replace('/DEFINER=`[^`]+`@`[^`]+`\s*/', '', $create_trigger[2]); 501 528 529 // Dynamicize Table Prefix (inside the trigger logic) 530 531 532 // Replace `prefix with `placeholder globally 533 $clean_sql = preg_replace("/`{$prefix_quoted}/", "`{$this->placeholder}", $clean_sql); 534 502 535 $output = "/*!50003 DROP TRIGGER IF EXISTS `$trigger_name` */;\n"; 503 536 $output .= "DELIMITER $$\n"; … … 521 554 } 522 555 523 $output = "\n--\n-- Table structure for table `$table_name`\n--\n\n"; 524 $output .= "DROP TABLE IF EXISTS `$table_name`;\n"; 525 $output .= $create_table[1] . ";\n\n"; 556 $prefix_quoted = preg_quote($this->db_prefix, '/'); 557 558 // Example: CREATE TABLE `wp_options` -> CREATE TABLE `{prefix}options` 559 $structure_sql = preg_replace( 560 "/`{$prefix_quoted}/", 561 "`{$this->placeholder}", 562 $create_table[1], 563 1 564 ); 565 if (strpos($table_name, $this->db_prefix) === 0) { 566 $dynamic_table_name = $this->placeholder . substr($table_name, strlen($this->db_prefix)); 567 } else { 568 // Backup external tables as-is if they don't share the WP prefix 569 $dynamic_table_name = $table_name; 570 } 571 572 $output = "\n--\n-- Table structure for table `$dynamic_table_name`\n--\n\n"; 573 $output .= "DROP TABLE IF EXISTS `$dynamic_table_name`;\n"; 574 $output .= $structure_sql . ";\n\n"; 526 575 fwrite($fp, $output); 527 576 } … … 544 593 return 0; 545 594 } 546 595 if (strpos($table_name, $this->db_prefix) === 0) { 596 $dynamic_table_name = $this->placeholder . substr($table_name, strlen($this->db_prefix)); 597 } else { 598 $dynamic_table_name = $table_name; 599 } 547 600 // Stream each row directly to the file 548 601 foreach ($rows as $row) { … … 550 603 $column_list = '`' . implode('`, `', $columns) . '`'; 551 604 $values = []; 605 606 552 607 553 608 foreach ($row as $value) { … … 561 616 } 562 617 } 563 564 $sql = "INSERT INTO `$ table_name` ($column_list) VALUES (" . implode(', ', $values) . ");\n";618 // We only change the table name in the INSERT statement. 619 $sql = "INSERT INTO `$dynamic_table_name` ($column_list) VALUES (" . implode(', ', $values) . ");\n"; 565 620 fwrite($fp, $sql); 566 621 } … … 620 675 621 676 622 public function create_zip_archive($sql_file, $zip_file )677 public function create_zip_archive($sql_file, $zip_file, $json_file = null) 623 678 { 624 679 $zip = new ZipArchive(); … … 628 683 629 684 $zip->addFile($sql_file, basename($sql_file)); 685 686 // Add JSON file if provided and exists 687 if ($json_file && file_exists($json_file)) { 688 $zip->addFile($json_file, basename($json_file)); 689 } 690 630 691 return $zip->close(); 631 692 } 632 633 693 public function verify_backup($zip_file) 634 694 { … … 692 752 public function write_backup_header($fp, $mysql_version) 693 753 { 694 global $wpdb;695 754 global $wpdb; 755 696 756 $header = "-- SurfLink\n"; 697 757 $header .= "-- site_url: " . site_url() . "\n"; 698 $header .= "-- prefix: " . $wpdb->prefix . "\n"; 758 $header .= "-- home_url: " . home_url() . "\n"; 759 $header .= "-- prefix: " . $wpdb->prefix . "\n"; 699 760 $header .= "-- WordPress Database Backup\n"; 700 761 $header .= "-- Version " . get_bloginfo('version') . "\n"; … … 732 793 public function log_error($message) 733 794 { 734 // error_log("Backup Error: " . $message);795 // error_log("Backup Error: " . $message); 735 796 $this->errors[] = $message; 736 797 } … … 1123 1184 } 1124 1185 1125 /**1186 /** 1126 1187 * Check if a file matches any of the exclusion rules. 1127 1188 * … … 1144 1205 // Clean the rule for matching (remove slashes from both ends) 1145 1206 // Example: "/backup*/" becomes "backup*" 1146 $clean_rule = trim($rule, '/'); 1207 $clean_rule = trim($rule, '/'); 1147 1208 1148 1209 if ($is_anchored) { … … 1159 1220 // Matches Rule "/backup*" against File "backup-2025/file.txt" 1160 1221 // But ignores File "test2/backup-2025/file.txt" 1161 1222 1162 1223 // Get the top-level folder name from the file path 1163 1224 $first_slash = strpos($relative_path, '/'); … … 1169 1230 1170 1231 // If anchored rule didn't match the root, stop here. 1171 continue; 1232 continue; 1172 1233 } 1173 1234 … … 1458 1519 $safe_subdir = trim(str_replace('\\', '/', $subdir)); 1459 1520 1460 // error_log("Checking if continue backup event is scheduled for subdir: " . $safe_subdir);1521 // error_log("Checking if continue backup event is scheduled for subdir: " . $safe_subdir); 1461 1522 1462 1523 if (empty($crons)) { … … 1540 1601 1541 1602 1542 public function is_module_enabled($slug)1603 public function is_module_enabled($slug) 1543 1604 { 1544 1605 $options = get_option('surfl_module_settings', []); … … 1557 1618 $options = get_option('surfl_module_settings', []); 1558 1619 if (isset($options[$slug]) && isset($options[$slug]['disable_background'])) { 1559 1620 1560 1621 return (int) $options[$slug]['disable_background']; 1561 1622 } … … 1573 1634 return false; 1574 1635 } 1575 1576 1577 1636 } -
surflink/trunk/includes/class-surfl-br-loader.php
r3429296 r3440991 11 11 require_once SURFL_PATH . 'includes/class-surfl-backup-helper.php'; 12 12 require_once SURFL_PATH . 'includes/class-surfl-restore-files.php'; 13 require_once SURFL_PATH . 'includes/class-surfl-br-replace-engine.php'; 13 14 14 15 … … 52 53 add_action('wp_ajax_surfl_upload_backup_file_chunk', [$this, 'ajax_upload_backup_file_chunk']); 53 54 add_action('wp_ajax_surfl_restore_uploaded_backup', [$this, 'run_restore']); 55 add_action('wp_ajax_surfl_run_db_replace', [$this, 'run_db_replace']); 54 56 55 57 … … 466 468 if (strpos($filename, 'database') !== false) { 467 469 470 $dir = dirname($filepath); 471 $json_info_file = $dir . '/db-info.json'; 468 472 469 473 470 474 $restore = new SURFL_Database_Restore(); 471 $result = $restore->restore_database_stream($filepath, $state); 475 476 if (!file_exists($json_info_file)) { 477 478 $result = $restore->old_restore_database_stream($filepath, $state); 479 } else { 480 481 $result = $restore->restore_database_stream($filepath, $state); 482 } 483 472 484 if ($result === false) { 473 485 throw new Exception('Database restore failed: ' . implode(', ', $restore->get_errors())); … … 475 487 if (!$result['done']) { 476 488 wp_send_json_success([ 477 'message' => "Restoring " .$result['current_table_name'] . ': ' . $result['rows_done'] . ' rows are restored.',489 'message' => $result['current_table_name'] . ': ' . $result['rows_done'] . ' rows are restored.', 478 490 'type' => $type, 479 491 'status' => 'ongoing', … … 481 493 ]); 482 494 } else { 495 496 497 498 if ($result['site_url_differed'] == '1' || $result['home_url_differed'] == '1') { 499 500 wp_send_json_success([ 501 'message' => "database imported. Now updating site URLs...", 502 'type' => $type, 503 'status' => 'replace_ongoing', 504 'state' => $result, 505 ]); 506 } 507 483 508 $is_last_uploaded_file && $this->cleanup_surflink_upload_dir(); 484 509 485 // error_log('Restoring ' . $type . ' completed.'); 510 486 511 487 512 … … 552 577 553 578 554 579 public function run_db_replace() 580 { 581 582 $this->check_nonce(); 583 if (!current_user_can('manage_options')) { 584 wp_send_json_error(['message' => 'Unauthorized']); 585 } 586 587 $filename = isset($_POST['filename']) ? sanitize_file_name($_POST['filename']) : ''; 588 $filepath = isset($_POST['filepath']) ? sanitize_text_field($_POST['filepath']) : ''; 589 590 591 $state_raw = $_POST['state'] ?? []; 592 $state = is_string($state_raw) ? json_decode(stripslashes($state_raw), true) : (is_array($state_raw) ? $state_raw : []); 593 594 595 596 if (empty($filename) || empty($filepath)) { 597 wp_send_json_error(['message' => 'Missing filename or filepath.']); 598 } 599 600 $type = 'database'; 601 $is_last_uploaded_file = isset($_POST['is_last_uploaded_file']) ? intval($_POST['is_last_uploaded_file']) : 0; 602 603 604 605 606 607 608 609 610 try { 611 612 if (strpos($filename, 'database') === false) { 613 614 615 throw new Exception('database replace operation failed'); 616 } 617 $replace = new SURFL_BR_REPLACE_ENGINE(); 618 $result = $replace->replace_database($filepath, $state); 619 if ($result === false) { 620 throw new Exception('Database URL replace failed.'); 621 } 622 if (!$result['done']) { 623 wp_send_json_success([ 624 'message' => $result['message'] ?? 'Searching and replacing URLs...', 625 'type' => $type, 626 'status' => 'replace_ongoing', 627 'state' => $result, 628 ]); 629 } else { 630 631 $is_last_uploaded_file && $this->cleanup_surflink_upload_dir(); 632 633 wp_send_json_success([ 634 'message' => "Database URLs restored and replaced successfully.", 635 'type' => $type, 636 'status' => 'success', 637 'state' => $result, 638 ]); 639 } 640 } catch (Exception $e) { 641 642 $is_last_uploaded_file && $this->cleanup_surflink_upload_dir(); 643 wp_send_json_error(['message' => $e->getMessage(), 'type' => $type]); 644 } 645 } 555 646 556 647 public function ajax_upload_backup_file_chunk() … … 782 873 $backup_dir = $this->backup_dir; 783 874 $file_path = $backup_dir . '/' . $subdir . '/' . $file; 875 $db_json = $backup_dir . '/' . $subdir . '/db-info.json'; 784 876 $file_name = str_replace('.zip', '', $file); 785 877 … … 799 891 // Add the original backup file into the surfl_backup.zip 800 892 $zip->addFile($file_path, basename($file_path)); 893 894 // Add the db-info.json file into the surfl_backup.zip 895 if (file_exists($db_json)) { 896 $zip->addFile($db_json, basename($db_json)); 897 } 801 898 $zip->close(); 802 899 … … 1209 1306 // status is 'completed' 1210 1307 1211 1308 1212 1309 $msg = 'Backup completed for database.'; 1213 1310 $status = 'success'; // Set status to success if no Google Drive upload -
surflink/trunk/includes/class-surfl-loginhider.php
r3437024 r3440991 159 159 * Blocks access to wp-login.php and redirects to 404 or Home. 160 160 */ 161 public function block_default_login() 162 { 163 // Don't block if we are actually on the custom login page (handled by rewrite) 164 if (get_query_var('surfl_custom_login')) { 165 return; 166 } 167 168 $pagenow = basename($_SERVER['SCRIPT_NAME']); 169 170 // Check if attempting to access wp-login.php directly 171 if ($pagenow === 'wp-login.php' && $_SERVER['REQUEST_METHOD'] === 'GET') { 172 173 // Allow logout and post-password actions 174 if (isset($_GET['action']) && in_array($_GET['action'], ['logout', 'postpass'])) { 175 return; 176 } 177 178 wp_safe_redirect(home_url()); 179 exit(); 180 } 181 } 161 public function block_default_login() 162 { 163 // Allow custom login page 164 if (get_query_var('surfl_custom_login')) { 165 return; 166 } 167 168 if (basename($_SERVER['SCRIPT_NAME']) !== 'wp-login.php') { 169 return; 170 } 171 172 173 if ($_SERVER['REQUEST_METHOD'] === 'POST') { 174 if ( 175 ! isset($_POST['surfl_login']) 176 ) { 177 wp_die(__('Forbidden', 'surfl'), 403); 178 } 179 180 return; 181 } 182 183 $action = isset($_GET['action']) 184 ? sanitize_text_field($_GET['action']) 185 : ''; 186 187 // Allow core WordPress actions 188 $allowed_actions = [ 189 'logout', 190 'postpass', 191 'lostpassword', 192 'resetpass', 193 'rp', 194 ]; 195 196 // Allow password reset links with key 197 if ($action && in_array($action, $allowed_actions, true)) { 198 return; 199 } 200 201 if (isset($_GET['key'])) { 202 return; 203 } 204 205 // Block direct access 206 wp_safe_redirect(home_url('/404'), 302); 207 exit; 208 } 209 182 210 /** 183 211 * Adds rewrite rules for the custom login URL -
surflink/trunk/includes/class-surfl-restore-db.php
r3429296 r3440991 9 9 10 10 private $start_time; 11 12 private $placeholder = '{temp_prefix_surflink}'; 11 13 12 14 public function __construct() { … … 50 52 51 53 public function restore_database_stream( $filename, $state = [] ) { 54 global $wpdb; 55 $fp = null; 56 $temp_path = WP_CONTENT_DIR . '/surflink/backup/restore/temp'; 57 $target_prefix = $wpdb->prefix; 58 // Disable query monitor during restore 59 add_filter( 'qm/enable', '__return_false', PHP_INT_MAX ); 60 try { 61 if ( empty( $filename ) || !file_exists( $filename ) ) { 62 $this->log( 'Backup file not found or empty filename: ' . $filename ); 63 throw new Exception('Backup file does not exist'); 64 } 65 $wpdb->suppress_errors( false ); 66 if ( $wpdb->query( 'SET AUTOCOMMIT=0' ) === false ) { 67 $this->log( 'Failed SET AUTOCOMMIT=0: ' . $wpdb->last_error ); 68 throw new Exception('Failed to set AUTOCOMMIT=0: ' . $wpdb->last_error); 69 } 70 if ( $wpdb->query( 'SET FOREIGN_KEY_CHECKS=0' ) === false ) { 71 $this->log( 'Failed SET FOREIGN_KEY_CHECKS=0: ' . $wpdb->last_error ); 72 throw new Exception('Failed to disable FK checks: ' . $wpdb->last_error); 73 } 74 if ( $wpdb->query( 'SET sql_notes=0' ) === false ) { 75 $this->log( 'Failed SET sql_notes=0: ' . $wpdb->last_error ); 76 throw new Exception('Failed to disable sql_notes: ' . $wpdb->last_error); 77 } 78 if ( $wpdb->query( 'START TRANSACTION' ) === false ) { 79 $this->log( 'Failed START TRANSACTION: ' . $wpdb->last_error ); 80 throw new Exception('Failed to start transaction: ' . $wpdb->last_error); 81 } 82 $this->log( 'Database session settings and transaction started successfully.', 'success' ); 83 if ( empty( $state ) ) { 84 $unique_slug = 'db-' . time(); 85 $temp_dir = $temp_path . '-' . $unique_slug; 86 if ( !SURFL_FS_Helper::mkdir( $temp_dir ) ) { 87 $this->log( 'Failed to create temporary directory: ' . $temp_dir ); 88 throw new Exception('Failed to create temporary directory'); 89 } 90 $free_space = @disk_free_space( WP_CONTENT_DIR ); 91 if ( $free_space !== false && $free_space < filesize( $filename ) * 2 ) { 92 $this->log( "❌ Not enough free space to extract zip." ); 93 throw new Exception("❌ Not enough free space to extract zip."); 94 } 95 try { 96 SURFL_FS_Helper::catch_disc_quota_error(); 97 $zip = new ZipArchive(); 98 if ( $zip->open( $filename ) !== true ) { 99 throw new Exception('Failed to open backup file'); 100 } 101 if ( !$zip->extractTo( $temp_dir ) ) { 102 $zip->close(); 103 throw new Exception('Failed to extract ZIP file'); 104 } 105 $zip->close(); 106 } finally { 107 restore_error_handler(); 108 } 109 $state = [ 110 'done' => false, 111 'unique_slug' => $unique_slug, 112 'position' => 0, 113 'current_table_name' => '', 114 'rows_done' => 0, 115 'table_prefix_differed' => 0, 116 'site_url_differed' => 0, 117 'home_url_differed' => 0, 118 'old_site_url' => '', 119 'old_home_url' => '', 120 'current_site_url' => SURFL_SITE_URL, 121 'current_home_url' => SURFL_HOME_URL, 122 'old_table_prefix' => '', 123 'current_table_prefix' => $target_prefix, 124 ]; 125 } 126 $temp_dir = $temp_path . '-' . $state['unique_slug']; 127 $position = intval( $state['position'] ); 128 $current_table_name = $state['current_table_name']; 129 $rows_done = intval( $state['rows_done'] ); 130 $sql_files = glob( $temp_dir . '/*.sql' ); 131 if ( empty( $sql_files ) ) { 132 throw new Exception('No SQL file found in backup'); 133 } 134 $sql_file = $sql_files[0]; 135 $this->log( 'SQL file for import: ' . $sql_file, 'success' ); 136 $fp = fopen( $sql_file, 'r' ); 137 if ( !$fp ) { 138 throw new Exception('Failed to open SQL file for reading'); 139 } 140 $site_url_differed = absint( $state['site_url_differed'] ); 141 $table_prefix_differed = absint( $state['table_prefix_differed'] ); 142 $home_url_differed = absint( $state['home_url_differed'] ); 143 if ( $position === 0 ) { 144 // --- MODIFIED: Read from db-info.json instead of parsing SQL header --- 145 $json_info_file = $temp_dir . '/db-info.json'; 146 if ( !file_exists( $json_info_file ) ) { 147 fclose( $fp ); 148 throw new Exception('Invalid backup: db-info.json not found in the backup archive.'); 149 } 150 $db_info = json_decode( file_get_contents( $json_info_file ), true ); 151 if ( json_last_error() !== JSON_ERROR_NONE || empty( $db_info ) ) { 152 fclose( $fp ); 153 throw new Exception('Invalid backup: db-info.json is corrupt or empty.'); 154 } 155 // 1. Site URL 156 if ( empty( $db_info['site_url'] ) ) { 157 fclose( $fp ); 158 throw new Exception('Invalid backup: Missing site_url in db-info.json'); 159 } 160 $backup_site_url = untrailingslashit( str_replace( '\\/', '/', $db_info['site_url'] ) ); 161 $current_site_url = untrailingslashit( site_url() ); 162 // 2. Home URL 163 if ( empty( $db_info['home_url'] ) ) { 164 fclose( $fp ); 165 throw new Exception('Invalid backup: Missing home_url in db-info.json'); 166 } 167 $backup_home_url = untrailingslashit( str_replace( '\\/', '/', $db_info['home_url'] ) ); 168 $current_home_url = untrailingslashit( home_url() ); 169 // 3. Table Prefix 170 if ( empty( $db_info['table_prefix'] ) ) { 171 fclose( $fp ); 172 throw new Exception('Invalid backup: Missing table_prefix in db-info.json'); 173 } 174 $backup_prefix = $db_info['table_prefix']; 175 $current_prefix = $wpdb->base_prefix; 176 // --- Comparisons --- 177 if ( $backup_site_url !== $current_site_url ) { 178 $site_url_differed = 1; 179 } 180 if ( $backup_home_url !== $current_home_url ) { 181 $home_url_differed = 1; 182 } 183 if ( $backup_prefix !== $current_prefix ) { 184 $table_prefix_differed = 1; 185 } 186 // Store in State 187 $state['old_site_url'] = $backup_site_url; 188 $state['old_home_url'] = $backup_home_url; 189 $state['old_table_prefix'] = $backup_prefix; 190 } 191 if ( $position > 0 ) { 192 fseek( $fp, $position ); 193 } 194 $current_query = ''; 195 $current_delimiter = ';'; 196 $line_num = 0; 197 $query_count = 0; 198 $row_count = 0; 199 $table_started = false; 200 $next_position = -1; 201 $is_sensitive_table = false; 202 $chunk_limit_reached = false; 203 while ( true ) { 204 $line_start_pos = ftell( $fp ); 205 $line = fgets( $fp ); 206 if ( $line === false ) { 207 // End of file 208 break; 209 } 210 $line_num++; 211 $trim_line = trim( $line ); 212 if ( stripos( $trim_line, 'DROP TABLE IF EXISTS' ) === 0 ) { 213 // Extract the potential new table name first 214 preg_match( '/DROP TABLE IF EXISTS `?([^`\\s]+)`?/i', $trim_line, $matches ); 215 $raw_table_name = ( !empty( $matches[1] ) ? $matches[1] : '' ); 216 if ( $raw_table_name == $this->placeholder . 'users' || $raw_table_name == $this->placeholder . 'usermeta' || $raw_table_name == $this->placeholder . 'options' ) { 217 $is_sensitive_table = true; 218 } 219 $new_table_name = ( $is_sensitive_table ? $raw_table_name : str_replace( $this->placeholder, $target_prefix, $raw_table_name ) ); 220 if ( $table_started ) { 221 $next_position = $line_start_pos; 222 break; 223 } 224 $table_started = true; 225 $current_table_name = $new_table_name; 226 // Update current_table_name to the newly found table 227 $rows_done = 0; 228 if ( !empty( $current_table_name ) ) { 229 $this->log( 'Processing table: ' . $current_table_name, 'success' ); 230 } 231 } 232 if ( preg_match( '/^\\/\\*!\\d+\\s+(.*?)\\*\\/;?\\s*$/s', $trim_line, $m ) ) { 233 $stmt = trim( $m[1], " ;\r\n\t" ); 234 if ( $stmt !== '' ) { 235 if ( $wpdb->query( $stmt ) === false ) { 236 throw new Exception('Versioned comment query failed: ' . $wpdb->last_error); 237 } 238 $query_count++; 239 } 240 continue; 241 } 242 $current_query .= $line; 243 if ( strlen( $current_query ) > 5 * 1024 * 1024 ) { 244 // 5 MB 245 $this->log( 'Query too large, skipping to prevent memory exhaustion' ); 246 throw new Exception('Oversized query detected'); 247 } 248 if ( stripos( $trim_line, 'DELIMITER ' ) === 0 ) { 249 $parts = preg_split( '/\\s+/', trim( substr( $trim_line, 9 ) ), 2 ); 250 if ( !empty( $parts[0] ) ) { 251 $current_delimiter = $parts[0]; 252 $current_query = ''; 253 continue; 254 } 255 } 256 // Robust parser loop inspired by split_sql_file 257 $in_string = false; 258 $in_backtick = false; 259 // Added for backtick quoted identifiers 260 $in_multiline_comment = false; 261 $query_buffer = ''; 262 $i = 0; 263 $len = strlen( $current_query ); 264 $delim_len = strlen( $current_delimiter ); 265 while ( $i < $len ) { 266 $char = $current_query[$i]; 267 $next_char = ( $i + 1 < $len ? $current_query[$i + 1] : '' ); 268 $next_next_char = ( $i + 2 < $len ? $current_query[$i + 2] : '' ); 269 // Handle multiline comments 270 if ( !$in_string && !$in_backtick ) { 271 if ( !$in_multiline_comment && $char == '/' && $next_char == '*' ) { 272 $in_multiline_comment = true; 273 $i += 2; 274 continue; 275 } 276 if ( $in_multiline_comment && $char == '*' && $next_char == '/' ) { 277 $in_multiline_comment = false; 278 $i += 2; 279 continue; 280 } 281 if ( $in_multiline_comment ) { 282 $i++; 283 continue; 284 } 285 } 286 // Handle strings and backticks 287 if ( $in_string ) { 288 if ( $char === $in_string && $current_query[$i - 1] !== '\\' ) { 289 // Check for unescaped quote 290 $in_string = false; 291 } 292 } elseif ( $in_backtick ) { 293 if ( $char === '`' && $current_query[$i - 1] !== '\\' ) { 294 // Check for unescaped backtick 295 $in_backtick = false; 296 } 297 } else { 298 if ( $char === "'" || $char === '"' ) { 299 $in_string = $char; 300 } elseif ( $char === '`' ) { 301 $in_backtick = true; 302 } 303 } 304 // Check for DELIMITER command 305 if ( !$in_string && !$in_backtick && !$in_multiline_comment && strtoupper( substr( $current_query, $i, 9 ) ) === 'DELIMITER' ) { 306 $i += 9; 307 $new_delim = ''; 308 while ( $i < $len && ($current_query[$i] === ' ' || $current_query[$i] === "\t") ) { 309 $i++; 310 } 311 while ( $i < $len && $current_query[$i] !== "\n" && $current_query[$i] !== "\r" ) { 312 $new_delim .= $current_query[$i]; 313 $i++; 314 } 315 $new_delim = trim( $new_delim ); 316 if ( !empty( $new_delim ) ) { 317 if ( !empty( trim( $query_buffer ) ) ) { 318 $q = ( $is_sensitive_table ? trim( $query_buffer ) : str_replace( $this->placeholder, $target_prefix, trim( $query_buffer ) ) ); 319 if ( $wpdb->query( $q ) === false ) { 320 $this->log( 'Query failed (line ' . $line_num . '): ' . $wpdb->last_error . ' | Snippet: ' . substr( $q, 0, 500 ) ); 321 throw new Exception('Query failed: ' . $wpdb->last_error); 322 } 323 $query_count++; 324 } 325 $query_buffer = ''; 326 $current_delimiter = $new_delim; 327 $delim_len = strlen( $current_delimiter ); 328 // Update delimiter length 329 } 330 while ( $i < $len && ($current_query[$i] === "\n" || $current_query[$i] === "\r") ) { 331 $i++; 332 } 333 continue; 334 } 335 // Check for current delimiter 336 if ( !$in_string && !$in_backtick && !$in_multiline_comment && substr( $current_query, $i, $delim_len ) === $current_delimiter ) { 337 $query_to_run = trim( $query_buffer ); 338 if ( !empty( $query_to_run ) ) { 339 $query_to_run = ( $is_sensitive_table ? trim( $query_to_run ) : str_replace( $this->placeholder, $target_prefix, $query_to_run ) ); 340 if ( $wpdb->query( $query_to_run ) === false ) { 341 $this->log( 'Query failed (line ' . $line_num . '): ' . $wpdb->last_error . ' | Snippet: ' . substr( $query_to_run, 0, 500 ) ); 342 throw new Exception('Query failed: ' . $wpdb->last_error); 343 } 344 $query_count++; 345 if ( stripos( ltrim( $query_to_run ), 'INSERT INTO' ) === 0 ) { 346 $row_count++; 347 // Break after 1000 rows 348 if ( $row_count >= 1000 || $this->time_exceeded() ) { 349 $next_position = ftell( $fp ); 350 // Save current file position 351 $chunk_limit_reached = true; 352 break 2; 353 // break out of while + parsing loop 354 } 355 } 356 } 357 $query_buffer = ''; 358 $i += $delim_len; 359 continue; 360 // Skip adding delimiter to buffer 361 } 362 $query_buffer .= $char; 363 $i++; 364 } 365 // After processing the current_query, move any remaining buffer to the next chunk 366 $current_query = $query_buffer; 367 $query_buffer = ''; 368 // Clear for next iteration 369 } 370 // Process any final query remaining in the buffer after EOF, but only if chunk limit was not reached 371 if ( !$chunk_limit_reached && !empty( trim( $current_query ) ) ) { 372 $cq = ( $is_sensitive_table ? trim( $current_query ) : str_replace( $this->placeholder, $target_prefix, trim( $current_query ) ) ); 373 if ( $wpdb->query( $cq ) === false ) { 374 $this->log( 'Final query failed: ' . $wpdb->last_error . ' | Snippet: ' . substr( $cq, 0, 500 ) ); 375 throw new Exception('Final query failed: ' . $wpdb->last_error); 376 } 377 $query_count++; 378 } 379 fclose( $fp ); 380 if ( $wpdb->query( 'COMMIT' ) === false ) { 381 throw new Exception('Failed to commit transaction: ' . $wpdb->last_error); 382 } 383 if ( $wpdb->query( 'SET FOREIGN_KEY_CHECKS=1' ) === false ) { 384 $this->log( 'Failed SET FOREIGN_KEY_CHECKS=1: ' . $wpdb->last_error ); 385 } 386 if ( $wpdb->query( 'SET sql_notes=1' ) === false ) { 387 $this->log( 'Failed SET sql_notes=1: ' . $wpdb->last_error ); 388 } 389 if ( $wpdb->query( 'SET AUTOCOMMIT=1' ) === false ) { 390 $this->log( 'Failed SET AUTOCOMMIT=1: ' . $wpdb->last_error ); 391 } 392 $latest_state = [ 393 'done' => false, 394 'unique_slug' => $state['unique_slug'], 395 'position' => $next_position, 396 'current_table_name' => $current_table_name, 397 'rows_done' => $row_count + $rows_done, 398 'current_site_url' => $state['current_site_url'], 399 'current_home_url' => $state['current_home_url'], 400 'current_table_prefix' => $state['current_table_prefix'], 401 'old_site_url' => $state['old_site_url'], 402 'old_home_url' => $state['old_home_url'], 403 'old_table_prefix' => $state['old_table_prefix'], 404 'site_url_differed' => $site_url_differed, 405 'table_prefix_differed' => $table_prefix_differed, 406 'home_url_differed' => $home_url_differed, 407 ]; 408 if ( $next_position !== -1 ) { 409 return $latest_state; 410 } else { 411 if ( $state['table_prefix_differed'] == 1 ) { 412 error_log( "Table prefix differed: {$state['old_table_prefix']} -> {$state['current_table_prefix']}" ); 413 $old_prefix = $state['old_table_prefix']; 414 $new_prefix = $state['current_table_prefix']; 415 $prefix_length_offset = strlen( $old_prefix ) + 1; 416 // 1. UPDATE USERMETA ({temp}usermeta) 417 // Targets: wp_capabilities, wp_user_level, etc. 418 // Note: Usermeta is still in the temporary table named "{temp}usermeta" 419 $temp_usermeta_table = $this->placeholder . 'usermeta'; 420 $wpdb->query( $wpdb->prepare( 421 "UPDATE `{$temp_usermeta_table}` \r\n SET meta_key = CONCAT(%s, SUBSTRING(meta_key, %d)) \r\n WHERE meta_key LIKE %s", 422 $new_prefix, 423 $prefix_length_offset, 424 $wpdb->esc_like( $old_prefix ) . '%' 425 ) ); 426 // 2. UPDATE OPTIONS (temp options table) 427 $temp_options_table = $this->placeholder . 'options'; 428 $wpdb->query( $wpdb->prepare( 429 "UPDATE `{$temp_options_table}` \r\n SET option_name = CONCAT(%s, SUBSTRING(option_name, %d)) \r\n WHERE option_name LIKE %s", 430 $new_prefix, 431 $prefix_length_offset, 432 $wpdb->esc_like( $old_prefix ) . '%' 433 ) ); 434 } 435 if ( $state['site_url_differed'] != 1 && $state['home_url_differed'] != 1 ) { 436 error_log( "state['site_url_differed'] != 1 && state['home_url_differed'] != 1" ); 437 //DROP and RENAME 438 $temp_prefix = $this->placeholder; 439 $target_prefix = $state['current_table_prefix']; 440 $wpdb->query( "DROP TABLE IF EXISTS `{$target_prefix}options`" ); 441 $wpdb->query( "RENAME TABLE `{$temp_prefix}options` TO `{$target_prefix}options`" ); 442 $wpdb->query( "DROP TABLE IF EXISTS `{$target_prefix}users`" ); 443 $wpdb->query( "RENAME TABLE `{$temp_prefix}users` TO `{$target_prefix}users`" ); 444 $wpdb->query( "DROP TABLE IF EXISTS `{$target_prefix}usermeta`" ); 445 $wpdb->query( "RENAME TABLE `{$temp_prefix}usermeta` TO `{$target_prefix}usermeta`" ); 446 } else { 447 error_log( "state['site_url_differed'] == 1 || state['home_url_differed'] == 1" ); 448 // 2. UPDATE OPTIONS (temp options table) 449 $temp_options_table = $this->placeholder . 'options'; 450 $wpdb->query( $wpdb->prepare( "UPDATE `{$temp_options_table}`\r\n SET option_value = %s\r\n WHERE option_name = 'siteurl'", $state['current_site_url'] ) ); 451 $wpdb->query( $wpdb->prepare( "UPDATE `{$temp_options_table}`\r\n SET option_value = %s\r\n WHERE option_name = 'home'", $state['current_home_url'] ) ); 452 } 453 } 454 $this->cleanup_temp_dir( $temp_dir ); 455 $latest_state['done'] = true; 456 return $latest_state; 457 // Signal completion 458 } catch ( Exception $e ) { 459 $this->log( $e->getMessage() ); 460 $wpdb->query( 'ROLLBACK' ); 461 $wpdb->query( 'SET FOREIGN_KEY_CHECKS=1' ); 462 $wpdb->query( 'SET sql_notes=1' ); 463 $wpdb->query( 'SET AUTOCOMMIT=1' ); 464 $this->log( 'Database transaction rolled back and settings reset due to error.' ); 465 if ( isset( $temp_dir ) && is_dir( $temp_dir ) ) { 466 if ( is_resource( $fp ) ) { 467 fclose( $fp ); 468 } 469 $this->cleanup_temp_dir( $temp_dir ); 470 } 471 return false; 472 } finally { 473 // Always run: restore Query Monitor 474 remove_filter( 'qm/enable', '__return_false', PHP_INT_MAX ); 475 } 476 } 477 478 public function old_restore_database_stream( $filename, $state = [] ) { 52 479 global $wpdb; 53 480 $fp = null; … … 112 539 'site_url' => SURFL_SITE_URL, 113 540 'home_url' => SURFL_HOME_URL, 541 'site_url_differed' => '0', 542 'home_url_differed' => '0', 114 543 ]; 115 544 } … … 372 801 'site_url' => $state['site_url'], 373 802 'home_url' => $state['home_url'], 803 'site_url_differed' => $state['site_url_differed'], 804 'home_url_differed' => $state['home_url_differed'], 374 805 ]; 375 806 if ( $next_position !== -1 ) { -
surflink/trunk/readme.txt
r3437024 r3440991 6 6 **Requires PHP:** 7.4 7 7 **Tested up to:** 6.9 8 **Stable tag:** 2.3. 88 **Stable tag:** 2.3.9 9 9 **License:** GPLv3 or later 10 10 **License URI:** https://opensource.org/licenses/GPL-3.0 … … 115 115 Yes! Database operations are powerful. Entering a wrong search or replace string could break your site. **Always** perform a Backup (using Module 3) before running a Search & Replace operation. Use the "Dry Run" feature first to verify what will be changed. 116 116 117 **Why can’t I restore the database backup on a different domain or table prefix?** 118 At the moment, SurfLink database restore only works on the same domain where the backup was created.This is a current technical limitation, not a permanent restriction. Support for restoring backups on a different domain or prefix(for example: staging, localhost, or a new production domain) is planned for a future release. 119 Current recommendations: 120 1. Restore the database on the original domain and table prefix. 121 2. Use a site migration plugin if you are moving to a new domain 117 **Can I restore the database backup on a different domain?** 118 Yes, SurfLink supports restoring datbase on a different domain (Multisite not supported). 119 Recommendations: 120 1.Upload the backup file from your old site. 121 2.Some plugins may be deactivated after restore, especially login security plugins. Reactivate them if needed. 122 3.The system automatically handles differences in database table prefixes. 123 4.If a plugin doesn’t work correctly after restore, try deactivating it and reactivating it. 124 5.Log in with the credentials from the old site. 125 126 **Can I restore the database backup on a different table prefix?** 127 Yes, the system automatically handles differences in database table prefixes. 122 128 123 129 **How does the Login Hider work?** … … 141 147 142 148 == Changelog == 149 150 = 2.3.9 = 151 * Fixed: Critical bug fixed in loginhider. 152 * New Feature: SurfLink now support cross domain restoration. 143 153 144 154 = 2.3.8 = -
surflink/trunk/surf-link.php
r3437024 r3440991 7 7 * Author: SurfLab 8 8 * Author URI: https://surflabtech.com 9 * Version: 2.3. 89 * Version: 2.3.9 10 10 * Text Domain: surflink 11 11 * License: GPL-3.0-or-later … … 67 67 } 68 68 if ( !defined( 'SURFL_VERSION' ) ) { 69 define( 'SURFL_VERSION', '2.3. 8' );69 define( 'SURFL_VERSION', '2.3.9' ); 70 70 } 71 71 if ( !defined( 'SURFL_PLUGIN' ) ) { … … 99 99 } 100 100 if ( !defined( 'SURFL_VERSION' ) ) { 101 define( 'SURFL_VERSION', '2.3. 8' );101 define( 'SURFL_VERSION', '2.3.9' ); 102 102 } 103 103 if ( !defined( 'SURFL_SITE_URL' ) ) { -
surflink/trunk/templates/login-template.php
r3437024 r3440991 32 32 <?php if (!$is_banned): ?> 33 33 <form name="loginform" id="loginform" action="<?php echo esc_url(home_url("/{$this->custom_login_slug}")); ?>" method="post"> 34 <p> 34 <input type="hidden" name="surfl_login" value="1"> 35 36 37 38 39 <p> 35 40 <label for="user_login"><?php esc_html_e('Username or Email', 'surflink'); ?></label> 36 41 <input type="text" name="log" id="user_login" class="input" value="" size="20" autocapitalize="off"> -
surflink/trunk/templates/surfl-restore-backup-html.php
r3429296 r3440991 14 14 15 15 16 <p class="surfl-flex-center" style="margin-top: 1rem;margin-bottom: 1rem;"> <span class="dashicons dashicons-warning"></span> Database restore works only on the original domain and table prefix(cross-domain support coming soon).</p> 17 <?php require_once SURFL_PATH . 'templates/surfl-backup-table.php' ?> 16 <?php require_once SURFL_PATH . 'templates/surfl-backup-table.php' ?> 17 <div class="surfl-instructions-wrapper" style="margin-top: 15px;"> 18 <span class="surfl-toggle-help"> 19 <span class="dashicons dashicons-info-outline"></span> <span class="surfl-toggle-text-span">How to migrate database (cross domain database restoration) ?</span> 20 </span> 21 22 <!-- NEW: HIDDEN INSTRUCTIONS BOX --> 23 <div id="surfl-csv-instructions" style="display:none;"> 24 25 <ol class="surfl-flex-col" style="gap:3px;"> 26 <li>It is not compitable with multisite, not yet.</li> 27 <li>Upload the backup file from your old site.</li> 28 <li>Some plugins may be deactivated after restore, especially login security plugins. Reactivate them if needed.</li> 29 <li>The system automatically handles differences in database table prefixes.</li> 30 <li>If a plugin doesn’t work correctly after restore, try deactivating it and reactivating it.</li> 31 <li>Log in with the credentials from the old site.</li> 18 32 33 34 </ol> 35 36 </div> 37 </div> 19 38 20 39 <!-- db file upload -->
Note: See TracChangeset
for help on using the changeset viewer.