# CONTRACT-SCANNER-PHP-ANALYZER-013: PHP Language Analyzer Bootstrap > **Status:** Published > **Version:** 1.0.0 > **Published:** 2025-12-05 > **Owners:** PHP Analyzer Guild, Scanner Guild > **Unblocks:** SCANNER-ANALYZERS-PHP-27-001 ## Overview This contract defines the PHP language analyzer bootstrap specification, including composer manifest parsing, VFS (Virtual File System) schema, and offline kit target requirements for deterministic PHP project analysis. ## Scope The PHP analyzer will: 1. Parse `composer.json` and `composer.lock` files 2. Build virtual file system from source trees, vendor directories, and configs 3. Detect framework/CMS fingerprints (Laravel, Symfony, WordPress, Drupal, etc.) 4. Emit SBOM components with PHP-specific PURLs 5. Support offline analysis via cached dependencies --- ## Input Normalization ### Source Tree Merge The analyzer merges these sources into a unified VFS: ``` Priority (highest to lowest): 1. /app (mounted application source) 2. /vendor (composer dependencies) 3. /etc/php* (PHP configuration) 4. Container layer filesystem ``` ### File Discovery ```csharp public interface IPhpSourceDiscovery { IAsyncEnumerable DiscoverAsync( string rootPath, PhpDiscoveryOptions options, CancellationToken ct); } public record PhpDiscoveryOptions { public bool IncludeVendor { get; init; } = true; public bool IncludeTests { get; init; } = false; public string[] ExcludePatterns { get; init; } = ["*.min.php", "cache/*"]; } ``` --- ## Composer Schema ### composer.json Parsing ```json { "name": "vendor/package", "version": "1.2.3", "type": "library|project|metapackage|composer-plugin", "require": { "php": ">=8.1", "vendor/dependency": "^2.0" }, "require-dev": { }, "autoload": { "psr-4": { "App\\": "src/" }, "classmap": ["database/"], "files": ["helpers.php"] } } ``` ### composer.lock Parsing Extract exact versions and content hashes: ```csharp public record ComposerLockPackage { public string Name { get; init; } public string Version { get; init; } public string Source { get; init; } // type: git|hg|svn public string Dist { get; init; } // type: zip|tar public string Reference { get; init; } // commit hash or tag public string ContentHash { get; init; } // SHA256 of package contents } ``` ### PURL Format ``` pkg:composer/vendor/package@version pkg:composer/laravel/framework@10.0.0 pkg:composer/symfony/http-kernel@6.3.0 ``` --- ## VFS Schema ### Virtual File System Model ```csharp public record PhpVirtualFileSystem { public string RootPath { get; init; } public IReadOnlyList Entries { get; init; } public PhpConfiguration PhpConfig { get; init; } public ComposerManifest Composer { get; init; } public string ContentHash { get; init; } // BLAKE3 of sorted entries } public record VfsEntry { public string RelativePath { get; init; } public VfsEntryType Type { get; init; } public long Size { get; init; } public string ContentHash { get; init; } public DateTimeOffset ModifiedAt { get; init; } } public enum VfsEntryType { PhpSource, PhpConfig, ComposerJson, ComposerLock, Vendor, Asset, Config } ``` ### Deterministic Ordering VFS entries MUST be sorted by: 1. `RelativePath` (case-sensitive, lexicographic) 2. Stable hash computation across runs --- ## Framework Detection ### Fingerprint Rules | Framework | Detection Method | Confidence | |-----------|-----------------|------------| | Laravel | `artisan` file + `Illuminate\` namespace | High | | Symfony | `symfony.lock` or `config/bundles.php` | High | | WordPress | `wp-config.php` + `wp-includes/` | High | | Drupal | `core/lib/Drupal.php` | High | | Magento | `app/etc/env.php` + `Magento\` namespace | High | | CodeIgniter | `system/core/CodeIgniter.php` | Medium | | Yii | `yii` or `yii2` in composer | Medium | | CakePHP | `cakephp/cakephp` in composer | Medium | ### Fingerprint Output ```csharp public record PhpFrameworkFingerprint { public string Name { get; init; } public string Version { get; init; } public ConfidenceLevel Confidence { get; init; } public IReadOnlyList IndicatorFiles { get; init; } } ``` --- ## PHP Configuration ### Config File Discovery ``` /etc/php/*/php.ini /etc/php/*/conf.d/*.ini /etc/php-fpm.d/*.conf /usr/local/etc/php/php.ini (Alpine) ``` ### Security-Relevant Settings Extract and report: ```csharp public record PhpSecurityConfig { public bool AllowUrlFopen { get; init; } public bool AllowUrlInclude { get; init; } public string OpenBasedir { get; init; } public string DisableFunctions { get; init; } public string DisableClasses { get; init; } public bool ExposePhp { get; init; } public bool DisplayErrors { get; init; } } ``` --- ## Output Schema ### SBOM Component ```json { "type": "library", "bom-ref": "pkg:composer/vendor/package@1.2.3", "purl": "pkg:composer/vendor/package@1.2.3", "name": "vendor/package", "version": "1.2.3", "properties": [ { "name": "stellaops:php:framework", "value": "laravel" }, { "name": "stellaops:php:phpVersion", "value": ">=8.1" }, { "name": "stellaops:php:autoload", "value": "psr-4" } ], "evidence": { "identity": { "field": "purl", "confidence": 1.0, "methods": [{ "technique": "manifest-analysis", "value": "composer.lock" }] } } } ``` ### Analysis Store Keys ```csharp public static class PhpAnalysisKeys { public const string VirtualFileSystem = "php.vfs"; public const string ComposerManifest = "php.composer"; public const string FrameworkFingerprints = "php.frameworks"; public const string SecurityConfig = "php.security-config"; public const string Autoload = "php.autoload"; } ``` --- ## Offline Kit Target ### Bundle Structure ``` offline/php-analyzer/ ├── manifests/ │ └── php-analyzer-manifest.json ├── fixtures/ │ ├── laravel-app/ │ ├── symfony-app/ │ └── wordpress-site/ ├── vendor-cache/ │ └── packages.json (Packagist mirror index) └── SHA256SUMS ``` ### Air-Gap Operation ```csharp public interface IOfflineComposerRepository { Task ResolveAsync(string name, string version, CancellationToken ct); Task IsAvailableOfflineAsync(string name, string version, CancellationToken ct); } ``` --- ## Test Fixtures ### Required Fixtures | Fixture | Purpose | |---------|---------| | `laravel-10-app/` | Laravel 10.x application with mix/vite | | `symfony-6-app/` | Symfony 6.x with Doctrine | | `wordpress-6-site/` | WordPress 6.x with plugins | | `drupal-10-site/` | Drupal 10.x with modules | | `composer-only/` | Pure library project | | `legacy-php56/` | PHP 5.6 compatibility test | ### Golden Output Format ``` fixtures// ├── composer.json ├── composer.lock ├── src/ ├── EXPECTED.sbom.json # Expected SBOM output ├── EXPECTED.vfs.json # Expected VFS structure └── EXPECTED.meta.json # Expected fingerprints ``` --- ## Implementation Path ### Phase 1: Core Parser 1. Implement `ComposerJsonParser` 2. Implement `ComposerLockParser` 3. Add PURL generation 4. Basic VFS construction ### Phase 2: Framework Detection 1. Implement fingerprint rules 2. Add confidence scoring 3. Version detection ### Phase 3: Offline Support 1. Implement vendor cache 2. Add offline repository 3. Bundle generation --- ## Project Location ``` src/Scanner/StellaOps.Scanner.Analyzers.Lang.Php/ ├── StellaOps.Scanner.Analyzers.Lang.Php.csproj ├── ComposerJsonParser.cs ├── ComposerLockParser.cs ├── PhpVirtualFileSystem.cs ├── PhpFrameworkDetector.cs ├── PhpLanguageAnalyzer.cs ├── PhpAnalyzerPlugin.cs └── README.md ``` --- ## Changelog | Version | Date | Author | Changes | |---------|------|--------|---------| | 1.0.0 | 2025-12-05 | PHP Analyzer Guild | Initial contract |