356 lines
11 KiB
PHP
356 lines
11 KiB
PHP
|
|
<?php
|
|||
|
|
/**
|
|||
|
|
* 清理 Composer 自动加载文件,移除已删除包的引用
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
$vendorDir = $argv[1] ?? '';
|
|||
|
|
if(empty($vendorDir) || !is_dir($vendorDir))
|
|||
|
|
{
|
|||
|
|
die("Usage: php cleanup_autoload.php <vendor_directory>\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$composerDir = $vendorDir . '/composer';
|
|||
|
|
if(!is_dir($composerDir))
|
|||
|
|
{
|
|||
|
|
die("Composer directory not found: $composerDir\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 要删除的包前缀
|
|||
|
|
$excludePackages = ['cweagans', 'laminas', 'markbaker', 'paragonie', 'phpseclib', 'symfony'];
|
|||
|
|
|
|||
|
|
echo "Cleaning up autoload files...\n";
|
|||
|
|
|
|||
|
|
// 清理 autoload_files.php
|
|||
|
|
$autoloadFilesPath = $composerDir . '/autoload_files.php';
|
|||
|
|
if(file_exists($autoloadFilesPath))
|
|||
|
|
{
|
|||
|
|
echo "Cleaning $autoloadFilesPath\n";
|
|||
|
|
|
|||
|
|
// 解析文件内容而不执行
|
|||
|
|
$fileContent = file_get_contents($autoloadFilesPath);
|
|||
|
|
preg_match_all("/'([^']+)' => \\\$vendorDir \. '([^']+)'/", $fileContent, $matches, PREG_SET_ORDER);
|
|||
|
|
|
|||
|
|
$filteredFiles = [];
|
|||
|
|
foreach($matches as $match)
|
|||
|
|
{
|
|||
|
|
$key = $match[1];
|
|||
|
|
$path = $match[2];
|
|||
|
|
|
|||
|
|
$shouldExclude = false;
|
|||
|
|
foreach($excludePackages as $package)
|
|||
|
|
{
|
|||
|
|
if(strpos($path, "/$package/") !== false)
|
|||
|
|
{
|
|||
|
|
$shouldExclude = true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if(!$shouldExclude)
|
|||
|
|
{
|
|||
|
|
$filteredFiles[$key] = "\$vendorDir . '$path'";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$content = "<?php\n\n// autoload_files.php @generated by Composer\n\n";
|
|||
|
|
$content .= "\$vendorDir = dirname(dirname(__FILE__));\n";
|
|||
|
|
$content .= "\$baseDir = dirname(\$vendorDir);\n\n";
|
|||
|
|
|
|||
|
|
// 手动生成数组,使用4个空格缩进
|
|||
|
|
$content .= "return array(\n";
|
|||
|
|
foreach($filteredFiles as $key => $file)
|
|||
|
|
{
|
|||
|
|
$content .= " '$key' => $file,\n";
|
|||
|
|
}
|
|||
|
|
$content .= ");\n";
|
|||
|
|
|
|||
|
|
file_put_contents($autoloadFilesPath, $content);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清理 autoload_psr4.php
|
|||
|
|
$autoloadPsr4Path = $composerDir . '/autoload_psr4.php';
|
|||
|
|
if(file_exists($autoloadPsr4Path))
|
|||
|
|
{
|
|||
|
|
echo "Cleaning $autoloadPsr4Path\n";
|
|||
|
|
|
|||
|
|
// 解析文件内容而不执行
|
|||
|
|
$fileContent = file_get_contents($autoloadPsr4Path);
|
|||
|
|
$filteredPsr4 = [];
|
|||
|
|
|
|||
|
|
// 匹配所有的命名空间映射 (包括array形式)
|
|||
|
|
preg_match_all("/'([^']+)' => array\(\\\$vendorDir \. '([^']+)'\)/", $fileContent, $arrayMatches, PREG_SET_ORDER);
|
|||
|
|
preg_match_all("/'([^']+)' => \\\$vendorDir \. '([^']+)'/", $fileContent, $directMatches, PREG_SET_ORDER);
|
|||
|
|
|
|||
|
|
// 处理array形式的匹配
|
|||
|
|
foreach($arrayMatches as $match)
|
|||
|
|
{
|
|||
|
|
$namespace = $match[1];
|
|||
|
|
$path = $match[2];
|
|||
|
|
|
|||
|
|
$shouldExclude = false;
|
|||
|
|
foreach($excludePackages as $package)
|
|||
|
|
{
|
|||
|
|
if(strpos($path, "/$package/") !== false)
|
|||
|
|
{
|
|||
|
|
$shouldExclude = true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if(!$shouldExclude)
|
|||
|
|
{
|
|||
|
|
$filteredPsr4[$namespace] = "array(\$vendorDir . '$path')";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理直接映射的匹配
|
|||
|
|
foreach($directMatches as $match)
|
|||
|
|
{
|
|||
|
|
$namespace = $match[1];
|
|||
|
|
$path = $match[2];
|
|||
|
|
|
|||
|
|
// 跳过已经在array形式中处理的
|
|||
|
|
if(isset($filteredPsr4[$namespace])) continue;
|
|||
|
|
|
|||
|
|
$shouldExclude = false;
|
|||
|
|
foreach($excludePackages as $package)
|
|||
|
|
{
|
|||
|
|
if(strpos($path, "/$package/") !== false)
|
|||
|
|
{
|
|||
|
|
$shouldExclude = true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if(!$shouldExclude)
|
|||
|
|
{
|
|||
|
|
$filteredPsr4[$namespace] = "\$vendorDir . '$path'";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$content = "<?php\n\n// autoload_psr4.php @generated by Composer\n\n";
|
|||
|
|
$content .= "\$vendorDir = dirname(dirname(__FILE__));\n";
|
|||
|
|
$content .= "\$baseDir = dirname(\$vendorDir);\n\n";
|
|||
|
|
|
|||
|
|
// 手动生成数组,使用4个空格缩进
|
|||
|
|
$content .= "return array(\n";
|
|||
|
|
foreach($filteredPsr4 as $namespace => $paths)
|
|||
|
|
{
|
|||
|
|
$content .= " '$namespace' => $paths,\n";
|
|||
|
|
}
|
|||
|
|
$content .= ");\n";
|
|||
|
|
|
|||
|
|
file_put_contents($autoloadPsr4Path, $content);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清理 autoload_classmap.php
|
|||
|
|
$autoloadClassmapPath = $composerDir . '/autoload_classmap.php';
|
|||
|
|
if(file_exists($autoloadClassmapPath))
|
|||
|
|
{
|
|||
|
|
echo "Cleaning $autoloadClassmapPath\n";
|
|||
|
|
|
|||
|
|
// 解析文件内容而不执行
|
|||
|
|
$fileContent = file_get_contents($autoloadClassmapPath);
|
|||
|
|
$filteredClassmap = [];
|
|||
|
|
|
|||
|
|
// 匹配所有的类映射
|
|||
|
|
preg_match_all("/'([^']+)' => \\\$vendorDir \. '([^']+)'/", $fileContent, $matches, PREG_SET_ORDER);
|
|||
|
|
|
|||
|
|
foreach($matches as $match)
|
|||
|
|
{
|
|||
|
|
$class = $match[1];
|
|||
|
|
$path = $match[2];
|
|||
|
|
|
|||
|
|
$shouldExclude = false;
|
|||
|
|
foreach($excludePackages as $package)
|
|||
|
|
{
|
|||
|
|
if(strpos($path, "/$package/") !== false)
|
|||
|
|
{
|
|||
|
|
$shouldExclude = true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if(!$shouldExclude)
|
|||
|
|
{
|
|||
|
|
$filteredClassmap[$class] = "\$vendorDir . '$path'";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$content = "<?php\n\n// autoload_classmap.php @generated by Composer\n\n";
|
|||
|
|
$content .= "\$vendorDir = dirname(dirname(__FILE__));\n";
|
|||
|
|
$content .= "\$baseDir = dirname(\$vendorDir);\n\n";
|
|||
|
|
|
|||
|
|
// 手动生成数组,使用4个空格缩进
|
|||
|
|
$content .= "return array(\n";
|
|||
|
|
foreach($filteredClassmap as $class => $path)
|
|||
|
|
{
|
|||
|
|
$content .= " '$class' => $path,\n";
|
|||
|
|
}
|
|||
|
|
$content .= ");\n";
|
|||
|
|
|
|||
|
|
file_put_contents($autoloadClassmapPath, $content);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清理 autoload_namespaces.php (PSR-0)
|
|||
|
|
$autoloadNamespacesPath = $composerDir . '/autoload_namespaces.php';
|
|||
|
|
$filteredPsr0 = [];
|
|||
|
|
if(file_exists($autoloadNamespacesPath))
|
|||
|
|
{
|
|||
|
|
echo "Cleaning $autoloadNamespacesPath\n";
|
|||
|
|
|
|||
|
|
// 解析文件内容而不执行
|
|||
|
|
$fileContent = file_get_contents($autoloadNamespacesPath);
|
|||
|
|
|
|||
|
|
// 匹配所有的PSR-0命名空间映射
|
|||
|
|
preg_match_all("/'([^']+)' => array\(\\\$vendorDir \. '([^']+)'\)/", $fileContent, $matches, PREG_SET_ORDER);
|
|||
|
|
|
|||
|
|
foreach($matches as $match)
|
|||
|
|
{
|
|||
|
|
$namespace = $match[1];
|
|||
|
|
$path = $match[2];
|
|||
|
|
|
|||
|
|
$shouldExclude = false;
|
|||
|
|
foreach($excludePackages as $package)
|
|||
|
|
{
|
|||
|
|
if(strpos($path, "/$package/") !== false)
|
|||
|
|
{
|
|||
|
|
$shouldExclude = true;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if(!$shouldExclude)
|
|||
|
|
{
|
|||
|
|
$filteredPsr0[$namespace] = "array(\$vendorDir . '$path')";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$content = "<?php\n\n// autoload_namespaces.php @generated by Composer\n\n";
|
|||
|
|
$content .= "\$vendorDir = dirname(dirname(__FILE__));\n";
|
|||
|
|
$content .= "\$baseDir = dirname(\$vendorDir);\n\n";
|
|||
|
|
|
|||
|
|
// 手动生成数组,使用4个空格缩进
|
|||
|
|
$content .= "return array(\n";
|
|||
|
|
foreach($filteredPsr0 as $namespace => $paths)
|
|||
|
|
{
|
|||
|
|
$content .= " '$namespace' => $paths,\n";
|
|||
|
|
}
|
|||
|
|
$content .= ");\n";
|
|||
|
|
|
|||
|
|
file_put_contents($autoloadNamespacesPath, $content);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清理 autoload_static.php
|
|||
|
|
$autoloadStaticPath = $composerDir . '/autoload_static.php';
|
|||
|
|
if(file_exists($autoloadStaticPath))
|
|||
|
|
{
|
|||
|
|
echo "Cleaning $autoloadStaticPath\n";
|
|||
|
|
$content = file_get_contents($autoloadStaticPath);
|
|||
|
|
|
|||
|
|
// 重新生成整个静态类
|
|||
|
|
preg_match('/class (ComposerStaticInit\w+)/', $content, $matches);
|
|||
|
|
$className = $matches[1] ?? 'ComposerStaticIniteb70fe9ec81c9f50588dedfb7a386792';
|
|||
|
|
|
|||
|
|
// 计算前缀长度(从已清理的PSR4数据)
|
|||
|
|
$prefixLengths = [];
|
|||
|
|
foreach(array_keys($filteredPsr4) as $namespace)
|
|||
|
|
{
|
|||
|
|
$firstChar = $namespace[0];
|
|||
|
|
if(!isset($prefixLengths[$firstChar]))
|
|||
|
|
{
|
|||
|
|
$prefixLengths[$firstChar] = [];
|
|||
|
|
}
|
|||
|
|
// 正确计算命名空间长度:将双反斜杠转换为单反斜杠后计算
|
|||
|
|
$actualNamespace = str_replace('\\\\', '\\', $namespace);
|
|||
|
|
$prefixLengths[$firstChar][$namespace] = strlen($actualNamespace);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 为 PSR-0 数据按首字母分组
|
|||
|
|
$psr0GroupedByFirstChar = [];
|
|||
|
|
foreach($filteredPsr0 as $namespace => $paths)
|
|||
|
|
{
|
|||
|
|
$firstChar = $namespace[0];
|
|||
|
|
if(!isset($psr0GroupedByFirstChar[$firstChar]))
|
|||
|
|
{
|
|||
|
|
$psr0GroupedByFirstChar[$firstChar] = [];
|
|||
|
|
}
|
|||
|
|
$psr0GroupedByFirstChar[$firstChar][$namespace] = $paths;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 使用我们刚刚过滤的数据
|
|||
|
|
$cleanFilesData = $filteredFiles;
|
|||
|
|
$cleanPsr4Data = $filteredPsr4;
|
|||
|
|
$cleanClassmapData = $filteredClassmap;
|
|||
|
|
$cleanPsr0Data = $psr0GroupedByFirstChar;
|
|||
|
|
|
|||
|
|
// 生成新的静态类内容
|
|||
|
|
$newContent = "<?php\n\n// autoload_static.php @generated by Composer\n\nnamespace Composer\Autoload;\n\n";
|
|||
|
|
$newContent .= "class $className\n{\n";
|
|||
|
|
|
|||
|
|
// Files 数组,使用4个空格缩进
|
|||
|
|
$newContent .= " public static \$files = array (\n";
|
|||
|
|
foreach($cleanFilesData as $key => $file)
|
|||
|
|
{
|
|||
|
|
$staticPath = str_replace('$vendorDir', "__DIR__ . '/..'", $file);
|
|||
|
|
$newContent .= " '$key' => $staticPath,\n";
|
|||
|
|
}
|
|||
|
|
$newContent .= " );\n\n";
|
|||
|
|
|
|||
|
|
// PrefixLengths 数组,使用4个空格缩进
|
|||
|
|
$newContent .= " public static \$prefixLengthsPsr4 = array (\n";
|
|||
|
|
foreach($prefixLengths as $firstChar => $prefixes)
|
|||
|
|
{
|
|||
|
|
$newContent .= " '$firstChar' => \n array (\n";
|
|||
|
|
foreach($prefixes as $prefix => $length)
|
|||
|
|
{
|
|||
|
|
$newContent .= " '$prefix' => $length,\n";
|
|||
|
|
}
|
|||
|
|
$newContent .= " ),\n";
|
|||
|
|
}
|
|||
|
|
$newContent .= " );\n\n";
|
|||
|
|
|
|||
|
|
// PSR4 数组,使用4个空格缩进
|
|||
|
|
$newContent .= " public static \$prefixDirsPsr4 = array (\n";
|
|||
|
|
foreach($cleanPsr4Data as $namespace => $paths)
|
|||
|
|
{
|
|||
|
|
$staticPath = str_replace(['array(', '$vendorDir', ')'], ['array (', "\n 0 => __DIR__ . '/..'", ",\n )"], $paths);
|
|||
|
|
$newContent .= " '$namespace' => \n $staticPath,\n";
|
|||
|
|
}
|
|||
|
|
$newContent .= " );\n\n";
|
|||
|
|
|
|||
|
|
// PSR-0 数组,使用4个空格缩进 (按首字母分组)
|
|||
|
|
$newContent .= " public static \$prefixesPsr0 = array (\n";
|
|||
|
|
foreach($cleanPsr0Data as $firstChar => $namespaces)
|
|||
|
|
{
|
|||
|
|
$newContent .= " '$firstChar' => \n array (\n";
|
|||
|
|
foreach($namespaces as $namespace => $paths)
|
|||
|
|
{
|
|||
|
|
$staticPath = str_replace(['array(', '$vendorDir', ')'], ['array (', "\n 0 => __DIR__ . '/..'", ",\n )"], $paths);
|
|||
|
|
$newContent .= " '$namespace' => \n $staticPath,\n";
|
|||
|
|
}
|
|||
|
|
$newContent .= " ),\n";
|
|||
|
|
}
|
|||
|
|
$newContent .= " );\n\n";
|
|||
|
|
|
|||
|
|
// Classmap 数组,使用4个空格缩进
|
|||
|
|
$newContent .= " public static \$classMap = array (\n";
|
|||
|
|
foreach($cleanClassmapData as $class => $path)
|
|||
|
|
{
|
|||
|
|
$staticPath = str_replace('$vendorDir', "__DIR__ . '/..'", $path);
|
|||
|
|
$newContent .= " '$class' => $staticPath,\n";
|
|||
|
|
}
|
|||
|
|
$newContent .= " );\n\n";
|
|||
|
|
|
|||
|
|
// 添加获取初始器方法
|
|||
|
|
$newContent .= " public static function getInitializer(ClassLoader \$loader)\n";
|
|||
|
|
$newContent .= " {\n";
|
|||
|
|
$newContent .= " return \\Closure::bind(function () use (\$loader) {\n";
|
|||
|
|
$newContent .= " \$loader->prefixLengthsPsr4 = {$className}::\$prefixLengthsPsr4;\n";
|
|||
|
|
$newContent .= " \$loader->prefixDirsPsr4 = {$className}::\$prefixDirsPsr4;\n";
|
|||
|
|
$newContent .= " \$loader->prefixesPsr0 = {$className}::\$prefixesPsr0;\n";
|
|||
|
|
$newContent .= " \$loader->classMap = {$className}::\$classMap;\n\n";
|
|||
|
|
$newContent .= " }, null, ClassLoader::class);\n";
|
|||
|
|
$newContent .= " }\n";
|
|||
|
|
$newContent .= "}\n";
|
|||
|
|
|
|||
|
|
file_put_contents($autoloadStaticPath, $newContent);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
echo "Autoload cleanup completed successfully!\n";
|