<?php
declare(strict_types=1);
try {
    $root=__DIR__;$expected=$argv[1]??'';
    if(!preg_match('/^[0-9a-f]{64}$/D',$expected)||hash_file('sha256',$root.'/manifest.json')!==$expected)throw new RuntimeException('Pinned manifest SHA mismatch');
    $m=json_decode(file_get_contents($root.'/manifest.json'),true);$s=json_decode(file_get_contents($root.'/source-identity.json'),true);
    ob_start();phpinfo(INFO_GENERAL);$general=ob_get_clean();preg_match('/PHP API\s*=>\s*(\d+)/',$general,$api);
    foreach(['version'=>PHP_VERSION,'API'=>$api[1]??null,'ZTS'=>PHP_ZTS,'int_size'=>PHP_INT_SIZE,'architecture'=>php_uname('m')] as $key=>$value)if($m['php'][$key]!==$value)throw new RuntimeException('PHP ABI mismatch '.$key);
    if(hash_file('sha256',PHP_BINARY)!==$s['php_binary']['sha256'])throw new RuntimeException('PHP binary changed');
    $cmd=explode("\0",file_get_contents('/proc/self/cmdline'));if(!in_array('-n',$cmd,true)||!in_array('extension='.$root.'/module/fileinfo.so',$cmd,true)||php_ini_loaded_file()!==false)throw new RuntimeException('Use standalone php -n with this exact private module');
    $files=$m['vendor_files'];if(count($files)!==54||$m['historical_appledouble_sidecars']!==63)throw new RuntimeException('Whitelist count drift');
    $actual=[];$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root.'/vendor',FilesystemIterator::SKIP_DOTS));foreach($it as $f){if($f->isLink())throw new RuntimeException('Cache symlink forbidden');if(!$f->isFile())continue;$rel=substr($f->getPathname(),strlen($root.'/vendor/'));if(strpos('/'.$rel,'/._')!==false)throw new RuntimeException('AppleDouble forbidden');$actual[$rel]=hash_file('sha256',$f->getPathname());if((fileperms($f->getPathname())&0222)!==0)throw new RuntimeException('Writable cached code');}ksort($actual);$wanted=$files;ksort($wanted);if($actual!==$wanted)throw new RuntimeException('Exact vendor whitelist/content mismatch');
    if(hash_file('sha256',$root.'/'.$m['module']['path'])!==$m['module']['sha256']||(fileperms($root.'/'.$m['module']['path'])&0222)!==0)throw new RuntimeException('Private module SHA/mode mismatch');
    foreach($m['helper_hashes'] as $rel=>$sha)if(hash_file('sha256',$root.'/'.$rel)!==$sha||(fileperms($root.'/'.$rel)&0222)!==0)throw new RuntimeException('Cache helper/content mode mismatch '.$rel);
    $allowed=$m['helper_hashes'];$allowed['manifest.json']=$expected;$allowed['manifest.sha256']=hash('sha256',$expected.'  manifest.json'."\n");$allowed[$m['module']['path']]=$m['module']['sha256'];foreach($files as $rel=>$sha)$allowed['vendor/'.$rel]=$sha;
    $all=[];$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root,FilesystemIterator::SKIP_DOTS));foreach($it as $f){if($f->isLink())throw new RuntimeException('Cache symlink forbidden');if(!$f->isFile())continue;$rel=substr($f->getPathname(),strlen($root)+1);if(!isset($allowed[$rel])||hash_file('sha256',$f->getPathname())!==$allowed[$rel]||(fileperms($f->getPathname())&0222)!==0)throw new RuntimeException('Unknown/writable/mismatched cache artifact '.$rel);$all[$rel]=true;}if(count($all)!==count($allowed))throw new RuntimeException('Incomplete whole-cache whitelist');
    $it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root,FilesystemIterator::SKIP_DOTS),RecursiveIteratorIterator::SELF_FIRST);foreach($it as $f)if($f->isDir()&&(fileperms($f->getPathname())&0222)!==0)throw new RuntimeException('Writable cache directory');if((fileperms($root)&0222)!==0)throw new RuntimeException('Writable cache root');
    if(!extension_loaded('fileinfo'))throw new RuntimeException('Native fileinfo not loaded');$finfo=new finfo(FILEINFO_MIME_TYPE);if($finfo->buffer(base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII='))!=='image/png')throw new RuntimeException('Native fileinfo fixed PNG probe');
    echo json_encode(['status'=>'PASS','manifest_sha256'=>$expected,'PHP_VERSION'=>PHP_VERSION,'PHP_API'=>$api[1],'PHP_ZTS'=>PHP_ZTS,'php_binary_sha256'=>$s['php_binary']['sha256'],'module_sha256'=>$m['module']['sha256'],'vendor_files_verified'=>count($actual),'AppleDouble_cached'=>0,'all_cache_directories_readonly'=>true,'native_fixed_PNG_mime'=>'image/png','business_HTTP'=>0,'business_DML'=>0,'network_calls'=>0]),"\n";
} catch(Throwable $e) {fwrite(STDERR,'Cache verification failed: '.$e->getMessage()."\n");exit(1);}
