fix(php8): statische Aufrufe, XAseco-Webaccess und TS3-count() fuer PHP 8 anpassen
- Php8Compat.php: nicht-statische Methoden, die als Klasse::methode() aufgerufen werden und kein $this nutzen, als static markieren (RemoteCP Core/Plugins, AdminServ Zip) - web_access.inc.php: Response als array() statt '' initialisieren (behebt Illegal string offset in web_access, xmlrpc_db, mania_karma) - plugin.teamspeak3.php: count() auf null entschaerft
This commit is contained in:
1 parent
b13b524ad5
commit
1ecb6c93b3
2 files changed
+165
-21
No files matched your search
+149
-21
@@ -16,6 +16,11 @@
|
||||
* Ausserdem werden String-Offsets mit geschweiften Klammern ($str{0}) auf
|
||||
* eckige Klammern umgestellt (unter PHP 8 ein Parse-Error).
|
||||
*
|
||||
* Nicht-statische Methoden, die statisch aufgerufen werden (Core::getObject()),
|
||||
* sind unter PHP 8 ein Fatal Error. Solche Methoden werden als static markiert,
|
||||
* sofern sie $this nicht verwenden und keine Unterklasse sie nicht-statisch
|
||||
* ueberschreibt.
|
||||
*
|
||||
* Idempotent: Klassen mit vorhandenem __construct() werden uebersprungen.
|
||||
* Dateien werden in-place geschrieben (Besitzer und Rechte bleiben erhalten).
|
||||
*/
|
||||
@@ -25,32 +30,155 @@ if ($argc < 2) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$totalFiles = 0;
|
||||
$totalClasses = 0;
|
||||
$totalCurly = 0;
|
||||
|
||||
$files = array();
|
||||
for ($i = 1; $i < $argc; $i++) {
|
||||
$dir = $argv[$i];
|
||||
if (!is_dir($dir)) continue;
|
||||
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS));
|
||||
if (!is_dir($argv[$i])) continue;
|
||||
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($argv[$i], FilesystemIterator::SKIP_DOTS));
|
||||
foreach ($it as $file) {
|
||||
if (strtolower($file->getExtension()) !== 'php') continue;
|
||||
$path = $file->getPathname();
|
||||
$src = file_get_contents($path);
|
||||
if ($src === false) continue;
|
||||
list($new, $count) = patchConstructors($src);
|
||||
list($new, $curly) = patchCurlyOffsets($new);
|
||||
if ($new !== $src) {
|
||||
file_put_contents($path, $new);
|
||||
$totalFiles++;
|
||||
$totalClasses += $count;
|
||||
$totalCurly += $curly;
|
||||
echo " $path: $count Konstruktor(en), $curly Offset(s)\n";
|
||||
}
|
||||
if (strtolower($file->getExtension()) === 'php') $files[] = $file->getPathname();
|
||||
}
|
||||
}
|
||||
|
||||
echo " PHP-8-Kompatibilitaet: $totalClasses Konstruktor(en), $totalCurly Offset(s) in $totalFiles Datei(en) angepasst.\n";
|
||||
$changed = array();
|
||||
$totalClasses = 0;
|
||||
$totalCurly = 0;
|
||||
$totalStatic = 0;
|
||||
|
||||
// Durchlauf 1: Konstruktoren und String-Offsets (pro Datei)
|
||||
foreach ($files as $path) {
|
||||
$src = file_get_contents($path);
|
||||
if ($src === false) continue;
|
||||
list($new, $count) = patchConstructors($src);
|
||||
list($new, $curly) = patchCurlyOffsets($new);
|
||||
if ($new !== $src) {
|
||||
file_put_contents($path, $new);
|
||||
$changed[$path] = true;
|
||||
$totalClasses += $count;
|
||||
$totalCurly += $curly;
|
||||
}
|
||||
}
|
||||
|
||||
// Durchlauf 2: statisch aufgerufene Methoden (dateiuebergreifend)
|
||||
foreach (patchStaticCalls($files) as $path => $count) {
|
||||
$changed[$path] = true;
|
||||
$totalStatic += $count;
|
||||
}
|
||||
|
||||
echo " PHP-8-Kompatibilitaet: $totalClasses Konstruktor(en), $totalCurly Offset(s), $totalStatic static-Methode(n) in " . count($changed) . " Datei(en) angepasst.\n";
|
||||
|
||||
/**
|
||||
* Markiert nicht-statische Methoden als static, wenn sie irgendwo als
|
||||
* Klasse::methode() aufgerufen werden, $this nicht verwenden und von keiner
|
||||
* Unterklasse nicht-statisch ueberschrieben werden.
|
||||
*
|
||||
* Liefert [Pfad => Anzahl geaenderter Methoden].
|
||||
*/
|
||||
function patchStaticCalls($files)
|
||||
{
|
||||
$methods = array(); // "klasse::methode" => [pfad, token-index, static, usesThis]
|
||||
$parents = array(); // "klasse" => "elternklasse"
|
||||
$calls = array(); // "klasse::methode" => true
|
||||
$tokensByFile = array();
|
||||
|
||||
foreach ($files as $path) {
|
||||
$src = file_get_contents($path);
|
||||
if ($src === false || strpos($src, '::') === false && stripos($src, 'class') === false) continue;
|
||||
$t = @token_get_all($src);
|
||||
$tokensByFile[$path] = $t;
|
||||
$n = count($t);
|
||||
$depth = 0;
|
||||
$cls = null;
|
||||
$clsDepth = -1;
|
||||
for ($i = 0; $i < $n; $i++) {
|
||||
$x = $t[$i];
|
||||
if ($x === '{' || (is_array($x) && in_array($x[0], array(T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES), true))) {
|
||||
$depth++;
|
||||
} elseif ($x === '}') {
|
||||
$depth--;
|
||||
if ($depth === $clsDepth) { $cls = null; $clsDepth = -1; }
|
||||
} elseif (is_array($x) && $x[0] === T_CLASS) {
|
||||
$prev = prevSignificant($t, $i);
|
||||
if ($prev !== null && is_array($t[$prev]) && in_array($t[$prev][0], array(T_DOUBLE_COLON, T_NEW), true)) continue;
|
||||
$j = nextSignificant($t, $i);
|
||||
if ($j !== null && is_array($t[$j]) && $t[$j][0] === T_STRING) {
|
||||
$cls = strtolower($t[$j][1]);
|
||||
$clsDepth = $depth;
|
||||
$e = nextSignificant($t, $j);
|
||||
if ($e !== null && is_array($t[$e]) && $t[$e][0] === T_EXTENDS) {
|
||||
$pc = nextSignificant($t, $e);
|
||||
if ($pc !== null && is_array($t[$pc])) $parents[$cls] = strtolower(ltrim($t[$pc][1], '\\'));
|
||||
}
|
||||
}
|
||||
} elseif ($cls !== null && is_array($x) && $x[0] === T_FUNCTION && $depth === $clsDepth + 1) {
|
||||
$static = false;
|
||||
for ($k = $i - 1; $k >= 0; $k--) {
|
||||
if (is_array($t[$k]) && $t[$k][0] === T_STATIC) $static = true;
|
||||
if ($t[$k] === ';' || $t[$k] === '{' || $t[$k] === '}') break;
|
||||
}
|
||||
$j = nextSignificant($t, $i);
|
||||
if ($j !== null && $t[$j] === '&') $j = nextSignificant($t, $j);
|
||||
if ($j === null || !is_array($t[$j])) continue;
|
||||
$m = strtolower($t[$j][1]);
|
||||
$usesThis = false;
|
||||
$k = $j;
|
||||
while ($k < $n && $t[$k] !== '{' && $t[$k] !== ';') $k++;
|
||||
if ($k < $n && $t[$k] === '{') {
|
||||
$d = 0;
|
||||
for ($q = $k; $q < $n; $q++) {
|
||||
$y = $t[$q];
|
||||
if ($y === '{' || (is_array($y) && in_array($y[0], array(T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES), true))) $d++;
|
||||
elseif ($y === '}') { $d--; if ($d === 0) break; }
|
||||
elseif (is_array($y) && $y[0] === T_VARIABLE && $y[1] === '$this') $usesThis = true;
|
||||
}
|
||||
}
|
||||
$methods["$cls::$m"] = array($path, $i, $static, $usesThis);
|
||||
} elseif (is_array($x) && $x[0] === T_DOUBLE_COLON && $i > 0 && isset($t[$i + 1])) {
|
||||
$p = $t[$i - 1];
|
||||
$nx = $t[$i + 1];
|
||||
if (is_array($p) && $p[0] === T_STRING && is_array($nx) && $nx[0] === T_STRING) {
|
||||
$j = nextSignificant($t, $i + 1);
|
||||
$c = strtolower($p[1]);
|
||||
if ($j !== null && $t[$j] === '(' && !in_array($c, array('parent', 'self', 'static'), true)) {
|
||||
$calls[$c . '::' . strtolower($nx[1])] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kandidaten je Datei sammeln (Token-Index der function-Deklaration)
|
||||
$todo = array();
|
||||
foreach ($calls as $key => $_) {
|
||||
if (!isset($methods[$key])) continue;
|
||||
list($path, $idx, $static, $usesThis) = $methods[$key];
|
||||
if ($static || $usesThis) continue;
|
||||
// Nicht anfassen, wenn eine Unterklasse die Methode nicht-statisch ueberschreibt
|
||||
list($target, $m) = explode('::', $key);
|
||||
$overridden = false;
|
||||
foreach ($methods as $other => $info) {
|
||||
list($oc, $om) = explode('::', $other);
|
||||
if ($om !== $m || $oc === $target || $info[2]) continue;
|
||||
for ($a = $oc, $guard = 0; isset($parents[$a]) && $guard < 20; $a = $parents[$a], $guard++) {
|
||||
if ($parents[$a] === $target) { $overridden = true; break 2; }
|
||||
}
|
||||
}
|
||||
if ($overridden) continue;
|
||||
$todo[$path][] = $idx;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach ($todo as $path => $indexes) {
|
||||
$t = $tokensByFile[$path];
|
||||
foreach ($indexes as $idx) {
|
||||
$t[$idx] = array(T_FUNCTION, 'static ' . $t[$idx][1], 0);
|
||||
}
|
||||
$out = '';
|
||||
foreach ($t as $tok) $out .= is_array($tok) ? $tok[1] : $tok;
|
||||
file_put_contents($path, $out);
|
||||
$result[$path] = count($indexes);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ersetzt String-Offsets mit geschweiften Klammern ($str{0}) durch eckige
|
||||
|
||||
@@ -426,6 +426,22 @@ if [ -f "$XASECO_MODERNIZER" ] && ! grep -q 'mysqli_report' "$XASECO_MODERNIZER"
|
||||
echo " modernizer.inc.php: mysqli_report(MYSQLI_REPORT_OFF) ergaenzt."
|
||||
fi
|
||||
|
||||
# XAseco: Webaccess initialisiert Antworten als '' statt array(). Schreib- und
|
||||
# Lesezugriffe wie $response['Code'] waren unter PHP 7 nur Warnings
|
||||
# ("Illegal string offset"), unter PHP 8 beenden sie XAseco (TypeError).
|
||||
XASECO_WEBACCESS="/opt/tmserver/xaseco/includes/web_access.inc.php"
|
||||
if [ -f "$XASECO_WEBACCESS" ] && grep -q "\['Response'\] = '';" "$XASECO_WEBACCESS"; then
|
||||
sed -i "s/\['Response'\] = '';/['Response'] = array();/" "$XASECO_WEBACCESS"
|
||||
echo " web_access.inc.php: Response als array() initialisiert."
|
||||
fi
|
||||
|
||||
# XAseco TeamSpeak3-Plugin: count() auf null ist unter PHP 8 ein TypeError
|
||||
XASECO_TS3="/opt/tmserver/xaseco/plugins/plugin.teamspeak3.php"
|
||||
if [ -f "$XASECO_TS3" ] && grep -qF "if ( count(\$info['players']) > 0 ) {" "$XASECO_TS3"; then
|
||||
sed -i "s/if ( count(\$info\['players'\]) > 0 ) {/if ( !empty(\$info['players']) \&\& is_array(\$info['players']) ) {/" "$XASECO_TS3"
|
||||
echo " plugin.teamspeak3.php: count()-Pruefung entschaerft."
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# XAseco: TeamSpeak3-Plugin Gateway aktualisieren (fuer bestehende Volumes)
|
||||
# ============================================================
|
||||
|
||||
Reference in new issue
Block a user