<?php
function env($key, $default=null) { static $vars=null; if ($vars===null){ $vars=[]; $file=__DIR__.'/../.env'; if(file_exists($file)){ $lines=file($file, FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); foreach($lines as $line){ $trim=trim($line); if($trim===''||$trim[0]==='#') continue; $parts=explode('=', $line, 2); if(count($parts)===2) $vars[trim($parts[0])] = trim($parts[1]); }}} return array_key_exists($key,$vars)?$vars[$key]:$default; }
if(!function_exists('str_starts_with')){ function str_starts_with($h,$n){ return strpos($h,$n)===0; }} if(!function_exists('str_ends_with')){ function str_ends_with($h,$n){ $l=strlen($n); if($l===0) return true; return substr($h,-$l)===$n; }}
function base_url($p='/'){ $b=rtrim((string)env('APP_BASE',''),'/'); $p='/'.ltrim($p,'/'); return $b.$p; } function asset_url($p){ return base_url('public/'.ltrim($p,'/')); }

function avatar_url($v){
    $v = (string)$v;
    $v = str_replace('\\','/',$v);
    if (preg_match('~^https?://~i',$v)) return $v;
    $file = basename($v);
    if ($file === '' || $file === '.' || $file === '..') return asset_url('uploads/avatars/default.png');
    $file = preg_replace('~[^A-Za-z0-9._-]~','',$file);
    return asset_url('uploads/avatars/'.$file);
}
function csrf_token(){ if(empty($_SESSION['csrf_token'])) $_SESSION['csrf_token']=bin2hex(random_bytes(32)); return $_SESSION['csrf_token']; }
function verify_csrf(){ if($_SERVER['REQUEST_METHOD']==='POST'){ $t=$_POST['_csrf']??''; if(!$t||!hash_equals($_SESSION['csrf_token']??'', $t)){ http_response_code(419); exit('CSRF token mismatch'); }}}
function set_flash($m){ $_SESSION['flash']=$m; } function get_flash(){ if(!isset($_SESSION['flash'])) return null; $r=$_SESSION['flash']; unset($_SESSION['flash']); return is_array($r)?json_encode($r,JSON_UNESCAPED_UNICODE):(string)$r; }
function view($n,$d=[]){ extract($d); $vf=__DIR__.'/views/'.$n.'.php'; if(!file_exists($vf)){ http_response_code(404); echo 'Vista no encontrada'; return;} include __DIR__.'/views/partials/_header.php'; include $vf; include __DIR__.'/views/partials/_footer.php'; }
function hash_password($p){ $algo=defined('PASSWORD_ARGON2ID')?PASSWORD_ARGON2ID:PASSWORD_DEFAULT; return password_hash($p,$algo);} function verify_password($p,$h){ return password_verify($p,$h);} function user(){ return $_SESSION['user']??null;} function require_auth(){ if(!user()) redirect(base_url('/login')); }
function redirect($p){ header('Location: '.$p); exit; } function ensure_dir($p){ if(!is_dir($p)) mkdir($p,0775,true);} function safe_filename($o){ $e=strtolower(pathinfo($o,PATHINFO_EXTENSION)); $n=bin2hex(random_bytes(12)); return $n.($e?('.'.$e):''); }
