znt/misc/cleanup_autoload.php

356 lines
11 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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