@@ -53,6 +53,40 @@ export const isFrontendFallback = (item: any) => item?.category === '前端库'
5353
5454const frontendTechnologyCategories = new Set ( [ '前端库' , '前端框架' , 'UI / CSS 框架' ] )
5555const frontendFallbackEvidencePattern = / ^ 兜 底 识 别 : /
56+ const phpRuntimeTechnologyNames = new Set (
57+ [
58+ 'WordPress' ,
59+ 'ThinkPHP' ,
60+ 'Discuz!' ,
61+ 'phpBB' ,
62+ 'Drupal' ,
63+ 'Joomla' ,
64+ 'Typecho' ,
65+ 'Z-BlogPHP' ,
66+ 'Emlog' ,
67+ 'Magento / Adobe Commerce' ,
68+ 'OpenCart' ,
69+ 'PrestaShop' ,
70+ 'DedeCMS' ,
71+ 'EmpireCMS' ,
72+ 'PHPCMS' ,
73+ 'PHPWind' ,
74+ 'BBSXP' ,
75+ 'HDWiki' ,
76+ 'MediaWiki' ,
77+ 'Laravel' ,
78+ 'Laravel Livewire' ,
79+ 'Symfony' ,
80+ 'Yii' ,
81+ 'CodeIgniter' ,
82+ 'CakePHP' ,
83+ 'Laminas / Zend Framework' ,
84+ 'Zend Framework' ,
85+ 'Swoole' ,
86+ 'OpenSwoole' ,
87+ 'FrankenPHP'
88+ ] . map ( normalizeTechName )
89+ )
5690
5791const frontendAliasTechnologies : Record < string , { category : string ; name : string ; url ?: string } > = {
5892 angular : { category : '前端框架' , name : 'Angular' } ,
@@ -96,6 +130,38 @@ export const cleanMergedTechnologyEvidence = (items: any[]) => {
96130 return evidence . filter ( item => ! isFrontendFallbackEvidence ( item ) )
97131}
98132
133+ const isPhpRuntimeTechnology = ( item : any ) =>
134+ item ?. category === '开发语言 / 运行时' && normalizeTechName ( item ?. name ) === normalizeTechName ( 'PHP' )
135+
136+ const isPhpRuntimeSourceTechnology = ( item : any ) => phpRuntimeTechnologyNames . has ( normalizeTechName ( item ?. name ) )
137+
138+ const phpRuntimeInferenceEvidence = ( item : any ) => {
139+ const name = String ( item ?. name || '' ) . trim ( ) || 'PHP 系技术'
140+ if ( item ?. category === '后端 / 服务器框架' ) {
141+ return `由 ${ name } 后端框架推断 PHP 后端运行时`
142+ }
143+ if ( item ?. category === '网站程序' || item ?. category === 'CMS / 电商平台' ) {
144+ return `由 ${ name } 站点程序推断 PHP 后端运行时`
145+ }
146+ return `由 ${ name } 技术线索推断 PHP 后端运行时`
147+ }
148+
149+ export const inferRuntimeTechnologiesFromDetectedTechnologies = ( items : any [ ] ) => {
150+ if ( ! Array . isArray ( items ) || ! items . length || items . some ( isPhpRuntimeTechnology ) ) return items
151+ const source = items . find ( isPhpRuntimeSourceTechnology )
152+ if ( ! source ) return items
153+ return [
154+ ...items ,
155+ {
156+ category : '开发语言 / 运行时' ,
157+ name : 'PHP' ,
158+ confidence : '中' ,
159+ evidence : [ phpRuntimeInferenceEvidence ( source ) ] ,
160+ source : '派生推断'
161+ }
162+ ]
163+ }
164+
99165const isWordPressThemeDirectoryFallbackEvidence = ( evidenceText : string ) =>
100166 / (?: 资 源 或 源 码 路 径 包 含 | 动 态 资 源 路 径 包 含 ) / i. test ( evidenceText ) && / \/ w p - c o n t e n t \/ t h e m e s \/ / i. test ( evidenceText )
101167
@@ -172,9 +238,10 @@ export const suppressWordPressThemeDirectoryFallbacks = (items: any[]) => {
172238
173239export const mergeTechnologyRecords = ( items : any [ ] ) => {
174240 const map = new Map < string , any > ( )
175- for ( const item of suppressDuplicateWebsiteProgramCategories (
241+ const normalizedItems = suppressDuplicateWebsiteProgramCategories (
176242 suppressWordPressThemeDirectoryFallbacks ( canonicalizeFrontendAliasTechnologies ( suppressFrontendFallbackDuplicates ( items ) ) )
177- ) ) {
243+ )
244+ for ( const item of inferRuntimeTechnologiesFromDetectedTechnologies ( normalizedItems ) ) {
178245 const key = `${ item . category } ::${ item . name } ` . toLowerCase ( )
179246 const current = map . get ( key ) || { ...item , evidence : [ ] }
180247 if ( ! current . url && item . url ) {
0 commit comments