403, 'body' => array('error' => 'Log in as an administrator first.')); } $write = isset($request['write']) && (string) $request['write'] === '1'; $nonce = isset($request['nonce']) ? (string) $request['nonce'] : ''; if ($write && !wp_verify_nonce($nonce, 'wpbr_host_probe')) { return array('status' => 403, 'body' => array('error' => 'Placing test files needs the nonce shown in the read-only report. Open the report, then use its write_link.')); } $want = isset($request['dir']) ? wpbr_storage_norm(sanitize_text_field((string) $request['dir'])) : ''; $domains = isset($request['domain']) ? array_map('sanitize_text_field', array_map('strval', (array) $request['domain'])) : array(); $chain = function ($path) { $hops = array(); $cur = (string) $path; for ($i = 0; $i < 8 && $cur !== '' && @is_link($cur); $i++) { $to = @readlink($cur); if ($to === false) break; $hops[] = $to; $cur = ($to !== '' && $to[0] === '/') ? $to : dirname($cur) . '/' . $to; } $real = $path !== '' ? @realpath($path) : false; return array('path' => $path, 'symlink_hops' => $hops, 'real' => $real === false ? null : $real); }; $mounts_text = @is_readable('/proc/mounts') ? (string) @file_get_contents('/proc/mounts') : ''; $mount_type = function ($path) use ($mounts_text) { $real = $path !== '' ? @realpath($path) : false; return $mounts_text !== '' && $real !== false ? wpbr_storage_mount_type($real, $mounts_text) : null; }; $free = function ($path) { $p = (string) $path; while ($p !== '' && $p !== '/' && !@is_dir($p)) $p = dirname($p); $f = function_exists('disk_free_space') ? @disk_free_space($p) : false; return $f === false ? null : (int) $f; }; $upload = wp_upload_dir(); $docs = wpbr_storage_document_roots(); $doc = isset($_SERVER['DOCUMENT_ROOT']) && is_string($_SERVER['DOCUMENT_ROOT']) ? sanitize_text_field(wp_unslash($_SERVER['DOCUMENT_ROOT'])) : ''; // Which front-proxy headers arrived, never their values: they carry visitors' addresses. $seen = array(); foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED_HOST', 'HTTP_X_FORWARDED_PROTO', 'HTTP_X_REAL_IP', 'HTTP_VIA', 'HTTP_X_FORWARDED_SERVER') as $k) { if (!empty($_SERVER[$k])) $seen[] = $k; } $report = array( 'generated_at' => gmdate('c'), 'reminder' => 'This is a temporary diagnostic. Delete the file when you are done (delete=1 with delete_nonce removes it).', 'environment' => array( 'php' => PHP_VERSION, 'sapi' => PHP_SAPI, 'uname' => php_uname('s r m'), 'wp_environment_type' => wp_get_environment_type(), 'server_software' => isset($_SERVER['SERVER_SOFTWARE']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_SOFTWARE'])) : null, 'front_proxy_headers_present' => $seen, 'open_basedir' => ini_get('open_basedir') ?: null, 'proc_mounts_readable' => $mounts_text !== '', 'container_signs' => wpbr_storage_in_container(), 'multisite' => is_multisite(), ), 'paths' => array( 'document_root' => $chain($doc), 'abspath' => $chain(ABSPATH), 'wp_content' => $chain(WP_CONTENT_DIR), 'uploads' => $chain($upload['basedir']), 'roots_the_plugin_knows' => $docs['roots'], 'mount_types' => array('document_root' => $mount_type($doc), 'uploads' => $mount_type($upload['basedir'])), ), 'plugin' => array( 'backups_dir' => wpbr_backups_dir(), 'active_location' => wpbr_storage_active_dir() ?: null, 'active_problem' => wpbr_storage_active_problem() ?: null, 'privacy_constants_set' => array('WPBR_PRIVATE_ROOT' => defined('WPBR_PRIVATE_ROOT'), 'WPBR_BACKUPS_DIR' => defined('WPBR_BACKUPS_DIR')), ), 'candidates' => array(), 'alias_probe' => array('requested' => $write), 'links' => array( 'write_link_template' => '?write=1&nonce=' . wp_create_nonce('wpbr_host_probe') . '&dir=&domain[]=', 'delete_nonce' => wp_create_nonce('wpbr_host_probe_delete'), ), ); $found = wpbr_storage_discover(array('probe' => false)); $by_path = array(); foreach (array_merge($found['eligible'], $found['rejected']) as $entry) { $props = array(); foreach ($entry['result']['properties'] as $name => $p) { $props[$name] = array_intersect_key($p, array_flip(array('status', 'detail', 'basis', 'fstype', 'colocated', 'mode'))); } $report['candidates'][] = array( 'path' => $entry['path'], 'source' => $entry['source'], 'eligible' => (bool) $entry['result']['ok'], 'mount_type' => $mount_type($entry['path']), 'free_bytes' => $free($entry['path']), 'properties' => $props, ); $by_path[$entry['path']] = true; } if ($write) { if ($want === '' || !isset($by_path[$want])) { $report['alias_probe'] = array('requested' => true, 'error' => 'dir must be one of the candidate paths listed in this report.'); } else { $probe = wpbr_storage_probe_aliases($want, array('hosts' => $domains)); $report['alias_probe'] = array('requested' => true, 'dir' => $want) + $probe + array( 'finding' => $probe['result'] === 'exposed' ? 'EXPOSED: ' . implode(', ', $probe['served']) : ($probe['result'] === 'not_exposed_on_tested_addresses' ? 'Not exposed on the addresses tested. This does not show that no mapping exists.' : 'Could not be checked.'), ); } } return array('status' => 200, 'body' => $report); }