dir;$env['ADMIN_COOKIE_SECURE']='0';$env['ADMIN_USERNAME']='test';$env['ADMIN_PASSWORD_HASH']=password_hash('fixture',PASSWORD_DEFAULT); $log=fopen($root.'/http.log','a');$server=proc_open([PHP_BINARY,'-S','127.0.0.1:'.$port,'-t',dirname(__DIR__).'/public',dirname(__DIR__).'/public/index.php'],[0=>['pipe','r'],1=>$log,2=>$log],$pipes,null,$env);$cookie=''; function presetRequest(string $method,string $path,?array $body=null,?string $csrf=null):array{global $port,$cookie;$headers=['Content-Type: application/json'];if($cookie)$headers[]='Cookie: '.$cookie;if($csrf!==null)$headers[]='X-CSRF-Token: '.$csrf;$ctx=stream_context_create(['http'=>['method'=>$method,'header'=>implode("\r\n",$headers),'content'=>$body===null?'':json_encode($body,JSON_THROW_ON_ERROR),'ignore_errors'=>true,'timeout'=>10]]);$raw=file_get_contents('http://127.0.0.1:'.$port.$path,false,$ctx);preg_match('~HTTP/\S+ (\d+)~',$http_response_header[0]??'',$m);foreach($http_response_header as $h)if(str_starts_with(strtolower($h),'set-cookie: '))$cookie=explode(';',substr($h,12))[0];return [(int)($m[1]??0),json_decode((string)$raw,true,64,JSON_THROW_ON_ERROR)];} try{ $deadline=microtime(true)+5;do{$socket=@fsockopen('127.0.0.1',$port);if($socket){fclose($socket);break;}usleep(20000);}while(microtime(true)<$deadline); foreach(['GET','POST','DELETE'] as $method){[$status]=presetRequest($method,'/api/utm-presets');httpCheck($status===401,'presets auth '.$method);} [$status,$login]=presetRequest('POST','/api/login',['username'=>'test','password'=>'fixture']);$csrf=$login['csrf']; $payload=['name'=>'HTTP набор','utm'=>Config::decode('{"theme":{"default":3,"weights":{"3":100}}}')]; foreach(['POST','DELETE'] as $method){[$status]=presetRequest($method,'/api/utm-presets',$payload);httpCheck($status===403,'presets CSRF '.$method);} [$status,$saved]=presetRequest('POST','/api/utm-presets',$payload,$csrf);httpCheck($status===201&&array_keys($saved['preset'])===['id','name','utm'],'HTTP creates strictly domain-free snapshot');$id=$saved['preset']['id']; [$status,$list]=presetRequest('GET','/api/utm-presets');httpCheck($status===200&&$list['presets']===[['id'=>$id,'name'=>'HTTP набор']],'global list without domain'); [$status]=presetRequest('GET','/api/utm-presets?target=anything');httpCheck($status===422,'domain list filter rejected'); [$status]=presetRequest('POST','/api/utm-presets',$payload,$csrf);httpCheck($status===409,'duplicate name conflict'); foreach(['source','domain','host','notes','target'] as $key){[$status]=presetRequest('POST','/api/utm-presets',$payload+[$key=>'forbidden'],$csrf);httpCheck($status===422,'reject preset binding or unrelated field '.$key);} [$status]=presetRequest('POST','/api/copy',['source'=>(object)['id'=>'old','version'=>str_repeat('a',64)],'targets'=>[]],$csrf);httpCheck($status===422,'legacy domain-copy API rejected'); [$status]=presetRequest('DELETE','/api/utm-presets',['id'=>$id],$csrf);httpCheck($status===200,'delete independent preset'); [$status]=presetRequest('DELETE','/api/utm-presets',['id'=>$id],$csrf);httpCheck($status===404,'repeat deletion returns not found'); [$status,$list]=presetRequest('GET','/api/utm-presets');httpCheck($list['presets']===[],'deleted preset absent from global list'); echo "Preset HTTP contract complete\n"; }finally{proc_terminate($server);proc_close($server);fclose($log);}