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";
|