<?php
final class Read7Gate {
 public static $lane='',$phase='preflight',$reads=0,$native=[],$denied=[],$journal=null;
 public const TABLES=['ydy_config','ydy_user','ydy_menu','ydy_user_data','ydy_department','ydy_staff_department','ydy_staff','ydy_identity_type','ydy_date_menu','ydy_dishes','ydy_consume_subsidy_batch','ydy_consume_subsidy_detail'];
 public static function append($e){if(is_resource(self::$journal)){fwrite(self::$journal,json_encode($e,JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION)."\n");fflush(self::$journal);}}
 public static function sql($sql,$role='store'){try{if($role!=='store')throw new RuntimeException('Read7 only actual primary queries');if($sql==='CALL SP_TABLEDEF(?, ?)')return;if(preg_match('/^SHOW (?:FULL )?COLUMNS FROM [`"]?(ydy_[a-z_]+)[`"]?$/iD',$sql,$m)){if(!in_array(strtolower($m[1]),self::TABLES,true))throw new RuntimeException('Metadata target');return;}$plain=preg_replace("/'(?:''|[^'])*'/s","''",trim($sql));if(!preg_match('/^SELECT\b/i',$plain)||preg_match('/;|--|\/\*|\b(INSERT|UPDATE|DELETE|MERGE|CREATE|ALTER|DROP|TRUNCATE|DO|CALL|EXEC|INTO|OUTFILE|DBLINK|SLEEP|BENCHMARK)\b/i',$plain))throw new RuntimeException('Hard SELECT only');preg_match_all('/\b(?:FROM|JOIN)\s+([`"]?[a-z_][a-z_0-9.$]*[`"]?)/i',$plain,$m);foreach($m[1]as $t)if(!in_array(strtolower(str_replace(['`','"'],'',$t)),array_merge(self::TABLES,['dual','information_schema.tables','information_schema.columns','user_tables','user_tab_columns','user_constraints','user_cons_columns','v$version']),true))throw new RuntimeException('Exact reviewed source table scope');}catch(Throwable $e){self::$denied[]=['SQL'=>$sql,'role'=>$role,'reason'=>$e->getMessage()];self::append(['event'=>'denied-before-PDO','SQL'=>$sql,'role'=>$role,'reason'=>$e->getMessage()]);throw $e;}}
 public static function budget(){foreach([['new-read',0,600],['total-read',self::$lane==='B'?713:836,self::$lane==='B'?1313:1436]]as $limit){$f=__DIR__.'/private/budget-'.$limit[0].'.json';$h=fopen($f,'c+');flock($h,LOCK_EX);$v=stream_get_contents($h);$n=$v===''?$limit[1]:(int)$v;if($n>=$limit[2])throw new RuntimeException('Unified new600/old cumulative cap');rewind($h);ftruncate($h,0);fwrite($h,(string)($n+1));flock($h,LOCK_UN);fclose($h);chmod($f,0600);}if(self::$phase==='preflight'&&++self::$reads>160)throw new RuntimeException('Preflight cap160 included in600');}
}
class Read7Statement extends PDOStatement {private $role,$binds=[];protected function __construct($role='store'){$this->role=$role;}public function bindValue($p,$v,$t=PDO::PARAM_STR){$ok=parent::bindValue($p,$v,$t);$this->binds[(string)$p]=['value'=>$v,'PDO_type'=>$t,'PHP_type'=>gettype($v),'ok'=>$ok];return $ok;}public function execute($params=null){Read7Gate::sql($this->queryString,$this->role);if($params!==null)throw new RuntimeException('Original explicit binds only');if($this->queryString==='CALL SP_TABLEDEF(?, ?)'){$v=array_column($this->binds,'value');if(count($v)!==2||$v[0]!=='ZHCT_APP'||!in_array($v[1],array_map('strtoupper',Read7Gate::TABLES),true))throw new RuntimeException('Exact original SP schema/table');}Read7Gate::budget();$r=['SQL'=>$this->queryString,'binds'=>$this->binds,'execute_parameters'=>$params,'success'=>false];Read7Gate::append(['event'=>'append-before','statement'=>$r]);try{$ok=parent::execute($params);$r['success']=$ok;$r['rowCount']=$this->rowCount();$r['errorInfo']=$this->errorInfo();return $ok;}catch(Throwable $e){$r['error']=['class'=>get_class($e),'message'=>$e->getMessage()];throw $e;}finally{Read7Gate::$native[]=$r;Read7Gate::append(['event'=>'original-native-result','statement'=>$r]);}}}
class Read7PDO extends PDO {public $role='store';public function prepare($sql,$o=[]){Read7Gate::sql($sql,$this->role);return parent::prepare($sql,$o);}public function query($sql,...$args){throw new RuntimeException('Original prepared path only');}public function exec($sql){Read7Gate::sql($sql,$this->role);throw new RuntimeException('No direct exec');}public function beginTransaction(){Read7Gate::$denied[]=['operation'=>'transaction'];throw new RuntimeException('No transaction');}public function lastInsertId($sequence=null){throw new RuntimeException('No inserts/identity');}}
