无法从外部versionen.php提取$software_version变量的问题排查
问题
将文件versionen.php存于所有已定义域名账户的"dataplace"文件夹中,尝试使用下方脚本读取并输出外部多个域名下该文件中的$software_version变量。该变量在本地可正常显示,脚本也能正确加载目标URL(已通过if ($content === false)的else分支验证),但测试输出中域名显示正常,$version却始终显示"Software-Empty",无法获取变量内容。
原脚本代码:
error_reporting(E_ALL); ini_set('display_errors', '1'); // FTP-Zugangsdaten für alle URLs (1 bis x) | FTP access data for all URLs (1 to x) $ftpCredentialsList = array( 1 => array("hostname" => "url-1.tld", "username" => "xxxxxxxx", "password" => "yyyyyyyy"), 2 => array("hostname" => "url-2.tld", "username" => "xxxxxxxx", "password" => "yyyyyyyy"), 3 => array("hostname" => "url-3.tld", "username" => "xxxxxxxx", "password" => "yyyyyyyy"), 4 => array("hostname" => "url-4.tld", "username" => "xxxxxxxx", "password" => "yyyyyyyy"), 5 => array("hostname" => "url-5.tld", "username" => "xxxxxxxx", "password" => "yyyyyyyy"), ); ########## Software-Release ########## // Funktion, um die Software-Version einer URL abzurufen | Function to retrieve the software version of a URL function getSoftwareVersion($url) { // cURL-Verbindung erstellen | Create cURL connection $curl = curl_init($url); // Optionen für cURL festlegen | Setting options for cURL curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // Folge Umleitungen | Follow redirects // Inhalt der Datei abrufen | Retrieve file contents $content = curl_exec($curl); if ($content === false) { die("Fehler beim Abrufen der Software-Version für $url: " . curl_error($curl)."| Error retrieving software version for $url: " . curl_error($curl)); } else { // echo 'Abruf der Software-Version für '.$url.' war erfolgreich. | Retrieving the software version for '.$url.' was successful.<br>'; } // Die Variable $software_version aus dem Inhalt extrahieren | Extract the variable $software_version from the content preg_match('/\$software_version\s*=\s*(.*?);/i', $content, $matches); $softwareVersion = isset($matches[1]) ? $matches[1] : null; // Debugging-Ausgabe | Debugging output echo "Regex-Matches: "; var_dump($matches); echo "<br>"; echo "Software-Version: "; var_dump($softwareVersion); echo "<br>"; // Ende Debugging curl_close($curl); return $softwareVersion; } // Ergebnisse speichern | Save results $softwareVersions = array(); foreach ($ftpCredentialsList as $index => $ftpCredentials) { $url = "https://{$ftpCredentials['hostname']}/dataplace/versionen.php"; $softwareVersion = getSoftwareVersion($url); // Überprüfen, ob die Software-Version gültig ist, bevor Farbe zugewiesen wird // Check if the software version is valid before assigning color $colorClass = 'software_empty'; // Standardfarbe, wenn die Software-Version leer ist | Default color if the software-version is empty if ($softwareVersion !== null) { $colorClass = (stripos($softwareVersion, 'software_red') !== false ? 'software_red' : 'software_green'); } // Ergebnisse in Array speichern | Save results in array $softwareVersions[$ftpCredentials['hostname']] = (empty($softwareVersion) ? "Software-Empty" : htmlspecialchars($softwareVersion)); // Farbinformationen zusätzlich speichern | Store additional color information $softwareVersions['color'][$ftpCredentials['hostname']] = $colorClass; } // Testausgabe | Test issue foreach ($softwareVersions as $hostname => $version) { if (!is_array($version)) { // Überprüfen, ob $version kein Array ist | Check if $version is not an array echo "<b>Hostname: <span style=\"color: #00F;\">$hostname</span> > Software-Version: <span style=\"color: #00F;\">$version</span><br>"; } }
解决方案
核心问题:HTTP请求获取的是PHP执行结果而非源代码
当你通过curl访问https://xxx/dataplace/versionen.php时,服务器会执行该PHP文件,返回的是文件的输出内容,而非PHP源码。如果versionen.php中仅定义了$software_version变量但没有输出语句,返回的内容为空,正则自然匹配不到变量定义。
解决方法二选一:
方法1:修改目标服务器的versionen.php,让它直接输出变量值
在versionen.php的末尾添加输出语句:
echo $software_version;
然后修改getSoftwareVersion函数,无需正则匹配,直接返回请求到的内容:
function getSoftwareVersion($url) { $curl = curl_init($url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); $content = curl_exec($curl); if ($content === false) { die("Fehler beim Abrufen der Software-Version für $url: " . curl_error($curl)."| Error retrieving software version for $url: " . curl_error($curl)); } curl_close($curl); // 直接返回获取到的输出内容(即$software_version的值) return trim($content); }
方法2:改用FTP读取PHP文件源代码
利用你已有的FTP凭证,直接连接服务器读取versionen.php的源码,再进行正则匹配。修改getSoftwareVersion函数为接收FTP凭证:
function getSoftwareVersion($ftpCredentials) { $hostname = $ftpCredentials['hostname']; $username = $ftpCredentials['username']; $password = $ftpCredentials['password']; $filePath = '/dataplace/versionen.php'; // 注意路径需符合服务器实际结构 // 建立FTP连接 $ftpConn = ftp_connect($hostname); if (!$ftpConn) { die("无法连接到FTP服务器 $hostname"); } // 登录FTP $loginStatus = ftp_login($ftpConn, $username, $password); if (!$loginStatus) { die("FTP登录失败 $hostname"); } // 切换到被动模式(大多数服务器需要) ftp_pasv($ftpConn, true); // 获取文件内容 ob_start(); $success = ftp_fget($ftpConn, STDOUT, $filePath, FTP_ASCII); $content = ob_get_clean(); if (!$success) { die("无法读取文件 $filePath 从 $hostname"); } ftp_close($ftpConn); // 优化正则,匹配带引号/不带引号的变量值 preg_match('/\$software_version\s*=\s*["\']?(.*?)["\']?;/i', $content, $matches); $softwareVersion = isset($matches[1]) ? trim($matches[1]) : null; return $softwareVersion; }
同时修改调用处的代码:
// 原代码中的foreach循环内修改: // $url = "https://{$ftpCredentials['hostname']}/dataplace/versionen.php"; // $softwareVersion = getSoftwareVersion($url); $softwareVersion = getSoftwareVersion($ftpCredentials);
其他优化点
- 正则表达式鲁棒性优化:如果使用方法2,原正则无法匹配带单/双引号的变量值,优化后的正则
/\$software_version\s*=\s*["\']?(.*?)["\']?;/i可以兼容多种定义格式。 - 数组结构优化:原代码中
$softwareVersions同时存储版本和颜色子数组,结构混乱,建议调整为每个主机对应一个子数组:
// 替换原结果存储部分 $softwareVersions[$ftpCredentials['hostname']] = [ 'version' => empty($softwareVersion) ? "Software-Empty" : htmlspecialchars($softwareVersion), 'color' => $colorClass ]; // 修改测试输出循环 foreach ($softwareVersions as $hostname => $info) { echo "<b>Hostname: <span style=\"color: #00F;\">$hostname</span> > Software-Version: <span class=\"{$info['color']}\">{$info['version']}</span><br>"; }
内容的提问来源于stack exchange,提问作者Fontane
相关产品推荐
相关产品推荐

