File: /var/www/api_matriculas/app/Helpers/functions_helper.php
<?php
use App\Repositories\ConfigurationRepository;
use App\Models\Configuration;
use Jenssegers\Agent\Agent;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Request;
function genericResponse($data, $code)
{
// Forzar conversión a entero para evitar errores de tipo
$code = (int) $code;
if ($code < 100 || $code > 599) {
$code = 500;
}
$data['hash'] = getToken();
// if ($code == 500) {
// $message = 'Error interno del servidor';
// $message = env('APP_ENV') == 'development' ? $message : 'Error interno del servidor';
// }
return response()->json($data, $code, [], JSON_INVALID_UTF8_SUBSTITUTE);
}
function getNoImage()
{
return getImagePath() . 'no-image.png';
}
function logoEmail()
{
return 'https://static.wixstatic.com/media/c6f5a1_897b296403f641159cfed8188b7f6537~mv2.png/v1/crop/x_190,y_556,w_1655,h_909/fill/w_350,h_184,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/IMG_4168_PNG.png';
return env('APP_URL') . getImagePath() . 'LogoBDF.png';
}
function getTemplate($template)
{
$public_folder = '';
if (env('TYPE_MODE') == 'PRODUCTION' || env('TYPE_MODE') == 'TEST') {
$public_folder = '/';
}
return env('APP_URL') . $public_folder . '/excel/' . $template;
}
function getImagePath()
{
$public_folder = '';
if (env('TYPE_MODE') == 'PRODUCTION' || env('TYPE_MODE') == 'TEST') {
$public_folder = '';
}
return $public_folder . 'assets/images/';
}
function validateRut($rut)
{
$r = strtoupper(preg_replace('/[^Kk0-9]/i', '', $rut));
// if ($r == '111111111' || $r == '222222222' || $r == '333333333' || $r == '444444444' || $r == '555555555' || $r == '666666666' || $r == '777777777' || $r == '888888888' || $r == '999999999') {
// return false;
// }
if (strlen($r) < 7) {
return false;
}
$sub_rut = substr($r, 0, strlen($r) - 1);
$sub_dv = substr($r, -1);
$x = 2;
$s = 0;
for ($i = strlen($sub_rut) - 1; $i >= 0; $i--) {
if ($x > 7) {
$x = 2;
}
$s += $sub_rut[$i] * $x;
$x++;
}
$dv = 11 - ($s % 11);
if ($dv == 10) {
$dv = 'K';
}
if ($dv == 11) {
$dv = '0';
}
if ($dv == $sub_dv) {
return true;
} else {
return false;
}
}
function strUpper($str)
{
$str = Str::upper(trim($str));
$str = str_replace('á', 'Á', $str);
$str = str_replace('é', 'É', $str);
$str = str_replace('í', 'Í', $str);
$str = str_replace('ó', 'Ó', $str);
$str = str_replace('ú', 'Ú', $str);
$str = str_replace('ñ', 'Ñ', $str);
return $str;
}
function strUpperSinTildes($str)
{
$str = Str::upper(trim($str));
$str = str_replace('á', 'A', $str);
$str = str_replace('Á', 'A', $str);
$str = str_replace('é', 'E', $str);
$str = str_replace('É', 'E', $str);
$str = str_replace('í', 'I', $str);
$str = str_replace('Í', 'I', $str);
$str = str_replace('ó', 'O', $str);
$str = str_replace('Ó', 'O', $str);
$str = str_replace('ú', 'U', $str);
$str = str_replace('Ú', 'U', $str);
$str = str_replace('ñ', 'Ñ', $str);
return $str;
}
function strLower($str)
{
$str = Str::lower(trim($str));
$str = str_replace('Á', 'á', $str);
$str = str_replace('É', 'é', $str);
$str = str_replace('Í', 'í', $str);
$str = str_replace('Ó', 'ó', $str);
$str = str_replace('Ú', 'ú', $str);
$str = str_replace('Ñ', 'ñ', $str);
return $str;
}
function strCapital($str)
{
$str = Str::lower(trim($str));
$str = str_replace('Á', 'á', $str);
$str = str_replace('É', 'é', $str);
$str = str_replace('Í', 'í', $str);
$str = str_replace('Ó', 'ó', $str);
$str = str_replace('Ú', 'ú', $str);
$str = str_replace('Ñ', 'ñ', $str);
return ucwords($str);
}
function formatterRut($rut, $dots = false)
{
$rutLimpio = str_replace('.', '', $rut);
$rutLimpio = trim(str_replace('-', '', $rutLimpio));
$dvRut = substr($rutLimpio, -1);
$rutLimpio = substr($rutLimpio, 0, -1);
$rutLimpio = clearMoney($rutLimpio);
if ($dots) {
$rutFormateado = format_number($rutLimpio) . '-' . $dvRut;
} else {
$rutFormateado = ($rutLimpio) . '-' . $dvRut;
}
return $rutFormateado;
}
function str_limit($value, $limit = '', $end = '')
{
if (empty($limit)) {
$limit = 100;
}
if (mb_strwidth($value, 'UTF-8') <= $limit) {
return $value;
}
return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')) . $end;
}
function getFormatMoney($amount, $currencyType)
{
// Asegurar tipo numérico
$amount = (float)$amount;
switch (strtoupper($currencyType)) {
case 'CLP':
case '$':
// Formato chileno sin decimales y con separador de miles
return $amount > 0
? '$' . number_format($amount, 0, ',', '.')
: '$0';
case 'UF':
// Mostrar hasta 3 decimales, eliminando ceros innecesarios
$formatted = number_format($amount, 3, '.', '');
[$integer, $decimal] = explode('.', $formatted);
$decimal = rtrim($decimal, '0');
$formattedUF = $decimal
? "{$integer},{$decimal} UF"
: "{$integer} UF";
return $formattedUF;
default:
// Genérico para otras monedas (ej: USD, EUR)
return number_format($amount, 2, ',', '.') . " {$currencyType}";
}
}
function format_money($numero)
{
if (!empty($numero)) {
$pesos = '$' . number_format($numero, 0, ',', '.');
} else {
$pesos = "No aplica";
}
return $pesos;
}
function format_number($numero)
{
if (!empty($numero)) {
$pesos = '' . number_format($numero, 0, ',', '.');
} else {
$pesos = "No aplica";
}
return $pesos;
}
function isUuid(string $value): bool
{
$pattern = '/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/';
return preg_match($pattern, $value) === 1;
}
function generateSecurePassword($length = 15)
{
// Definir los caracteres permitidos
$upperCase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$lowerCase = 'abcdefghijklmnopqrstuvwxyz';
$numbers = '0123456789';
$specialCharacters = '!@#$%^&*()_+-=[]{}|;:,.<>?';
// Combinar todos los caracteres en un solo string
$allCharacters = $upperCase . $lowerCase . $numbers . $specialCharacters;
// Asegurarse de que la contraseña contenga al menos un carácter de cada tipo
$password = '';
$password .= $upperCase[random_int(0, strlen($upperCase) - 1)];
$password .= $lowerCase[random_int(0, strlen($lowerCase) - 1)];
$password .= $numbers[random_int(0, strlen($numbers) - 1)];
$password .= $specialCharacters[random_int(0, strlen($specialCharacters) - 1)];
// Llenar el resto de la contraseña con caracteres aleatorios
for ($i = 4; $i < $length; $i++) {
$password .= $allCharacters[random_int(0, strlen($allCharacters) - 1)];
}
// Mezclar la contraseña para evitar un patrón predecible
return str_shuffle($password);
}
function getToken()
{
return sha1(strtotime(now()));
}
function sortDateHourForHuman($date)
{
$explode = explode(" ", $date);
$fecha[] = implode('-', array_reverse(explode('-', $explode[0])));
$tiempo = explode(":", $explode[1]);
$fecha[] = $tiempo[0] . ':' . $tiempo[1];
return implode(' ', $fecha);
}
function limpiarStr($str)
{
$str = trim($str);
$str = str_replace('á', 'a', $str);
$str = str_replace('é', 'e', $str);
$str = str_replace('í', 'i', $str);
$str = str_replace('ó', 'o', $str);
$str = str_replace('ú', 'u', $str);
$str = str_replace('año', 'annio', $str);
$str = str_replace('ñ', 'n', $str);
return $str;
}
function getSlug($str, $lower = true, $separator = '-')
{
$str = trim($str);
if ($lower) {
$str = strLower($str);
}
$str = str_replace('"', '', $str);
$str = limpiarStr($str);
$str = preg_replace('([^A-Za-z0-9])', $separator, $str);
return $str;
}
function ordenar_fechaHoraServidor($date = '')
{
if (empty($date)) {
$date = date('Y-m-d');
}
$date = new DateTime($date);
$fechaFormat = $date->format('Y-m-d H:i:s');
return $fechaFormat;
}
function sort_dateServer($date)
{
$date = new DateTime($date);
$fechaFormat = $date->format('Y-m-d H:i:s');
return $fechaFormat;
}
function sort_datetimeHuman($date)
{
$date = new DateTime($date);
$fechaFormat = $date->format('d-m-Y H:i:s');
return $fechaFormat;
}
function ordenar_fechaHumano($date)
{
$explode = explode(" ", $date);
$fecha = implode('-', array_reverse(explode('-', $explode[0])));
return $fecha;
}
function ordenarFechaHumanoSlash($date)
{
$explode = explode(" ", $date);
$fecha = implode('/', array_reverse(explode('-', $explode[0])));
return $fecha;
}
function ordenar_fechaHoraHumano($date)
{
$explode = explode(" ", $date);
$fecha[] = implode('-', array_reverse(explode('-', $explode[0])));
$tiempo = explode(":", $explode[1]);
$fecha[] = $tiempo[0] . ':' . $tiempo[1];
return implode(' ', $fecha);
}
function ordenar_fechaHoraMinutoHumano($date)
{
$explode = explode(" ", $date);
$fecha[] = implode('-', array_reverse(explode('-', $explode[0])));
$fecha[] = $explode[1];
return implode(' ', $fecha);
}
function transformDateTextMonth($fecha = '', $shortMonth = false, $separator = ' ')
{
if (empty($fecha)) {
$fecha = date('Y-m-d');
}
$day = date("d", strtotime($fecha));
$month = date("m", strtotime($fecha));
if ($shortMonth) {
$month = getMonthShort($month);
} else {
$month = getMonth($month);
}
$year = date("Y", strtotime($fecha));
$date_formatted = $day . $separator . ($month) . $separator . $year;
return trim($date_formatted);
}
function getMonthShort($mes)
{
$return = '';
$meses = array(
1 => "Ene",
2 => "Feb",
3 => "Mar",
4 => "Abr",
5 => "May",
6 => "Jun",
7 => "Jul",
8 => "Ago",
9 => "Sep",
10 => "Oct",
11 => "Nov",
12 => "Dic"
);
foreach ($meses as $key => $value) {
if ($key == $mes) {
$return = $value;
}
}
return $return;
}
function getMonth($mes)
{
$return = '';
$meses = array(
1 => "Enero",
2 => "Febrero",
3 => "Marzo",
4 => "Abril",
5 => "Mayo",
6 => "Junio",
7 => "Julio",
8 => "Agosto",
9 => "Septiembre",
10 => "Octubre",
11 => "Noviembre",
12 => "Diciembre"
);
foreach ($meses as $key => $value) {
if ($key == $mes) {
$return = $value;
}
}
return $return;
}
function getUserConnection()
{
$agent = new Agent();
return (object)[
'ip' => Request::ip(),
'login_at' => now()->format('Y-m-d H:i:s'),
'navegador' => $agent->browser() . ' Version: ' . $agent->version($agent->browser()),
'dispositivo' => $agent->isMobile() ? 'Dispositivo Móvil' : 'Escritorio',
];
}
function clearMoney($str)
{
$str = trim($str);
$str = str_replace('$', '', $str);
$str = str_replace('.', '', $str);
$str = preg_replace('([^0-9])', '', $str);
return $str;
}
/**
* Calcula el precio neto (sin IVA) desde un precio con IVA, redondeado a entero.
*
* @param float|int $price Precio con IVA
* @param float $tax Porcentaje de IVA (por defecto 19%)
* @return int Precio sin IVA
*/
function priceWithoutTax($price, $tax = 19)
{
return round($price / (1 + $tax / 100), 0);
}
function getStatusOrders()
{
return [
'auto-draft' => 'Borrador',
'cancelled' => 'Cancelado',
'completed' => 'Completado',
'failed' => 'Fallido',
'processing' => 'En Proceso',
'refunded' => 'Reembolsado',
'pendient' => 'En Curso'
];
}
function cleanDescription($text)
{
// Reemplazar \r\n, \n, \r, tabulaciones y espacios no rompibles por espacios normales
$text = str_replace(["\r\n", "\r", "\n", "\t", "\u{A0}"], ' ', $text);
// Eliminar múltiples espacios seguidos
$text = preg_replace('/\s+/', ' ', $text);
// Recortar espacios al inicio y final
return trim($text);
}
function getMonthText($month)
{
$return = '';
$months = array(
1 => "Enero",
2 => "Febrero",
3 => "Marzo",
4 => "Abril",
5 => "Mayo",
6 => "Junio",
7 => "Julio",
8 => "Agosto",
9 => "Septiembre",
10 => "Octubre",
11 => "Noviembre",
12 => "Diciembre"
);
if ($months[$month]) {
$return = $months[$month];
}
return $return;
}
function formattedStudents($students = [])
{
if (empty($students)) return '';
$html = '<table style="width:100%; font-family: Arial, sans-serif; font-size:9pt; border-collapse:collapse; line-height:1.4; margin-top:-20px;margin-bottom:-5px">';
foreach ($students as $student) {
$full_name = trim("{$student->first_name} {$student->second_name} {$student->last_name} {$student->second_last_name}");
$rut = formatterRut($student->rut, true);
$course = $student->course_id > 0 ? $student->course->course : "Sin información";
$html .= '
<tr>
<td style="width:50%; white-space:nowrap;">
<span>Nombre alumno: </span>
<span style="display:inline-block; width:65%; border-bottom:1px solid #000;margin-top:2px">
<strong style="padding:0px; margin:0px;font-size:8.5pt;">' . htmlspecialchars($full_name) . '</strong>
</span>
</td>
<td style="width:25%; white-space:nowrap;">
<span>RUT N°: </span>
<span style="display:inline-block; width:65%; border-bottom:1px solid #000;margin-top:2px">
<strong style="padding:0px; margin:0px;font-size:8.5pt;">' . htmlspecialchars($rut) . '</strong>
</span>
</td>
<td style="width:25%; white-space:nowrap;">
<span>Curso: </span>
<span style="display:inline-block; width:70%; border-bottom:1px solid #000;margin-top:2px">
<strong style="padding:0px; margin:0px;font-size:8.5pt;">' . htmlspecialchars(strCapital($course)) . '</strong>
</span>
</td>
</tr>';
}
$html .= '</table>';
return $html;
}
function formattedTableConcepts($paymentConcept, $typePrice = 'regular')
{
$paymentConceptDetails = $paymentConcept->details ?? [];
$html = "";
$table = '<table border="1" cellpadding="1" cellspacing="1" style="width:500px">
<tbody>
<tr>
<td style="text-align:center"><span style="font-size:11pt"><span style="font-family:"Arial MT",sans-serif"><strong><span style="font-size:9.0pt"><span style="font-family:"Arial",sans-serif">Niveles</span></span></strong></span></span></td>
<td style="text-align:center"><span style="font-size:11pt"><span style="font-family:"Arial MT",sans-serif"><strong><span style="font-size:9.0pt"><span style="font-family:"Arial",sans-serif">Colegiatura Anual</span></span></strong></span></span></td>
</tr>
#details
</tbody>
</table>';
$formatMoney = $paymentConcept->currency_type_id > 0 ? $paymentConcept->currency_type->currency_symbol : '$';
foreach ($paymentConceptDetails as $key => $row) {
$price = $typePrice == 'exceptional' ? $row->price_exceptional : ($typePrice == 'cae' ? $row->price_cae : $row->price_regular);
$html .= '<tr>
<td style="text-align:center"><span style="font-size:11pt"><span style="font-family:"Arial MT",sans-serif"><span style="font-size:9.0pt">' . $row->description . '</span></span></span></td>
<td style="text-align:center"><span style="font-size:11pt"><span style="font-family:"Arial MT",sans-serif"><span style="font-size:9.0pt"><span style="font-family:"Arial",sans-serif">' . $formatMoney . ' ' . ($formatMoney == '$' ? format_number($price) : $price) . '</span></span></span></span></td>
</tr>';
}
$table = str_replace('#details', $html, $table);
return $table;
}
function signatureSection(){
return '<table align="left" cellspacing="0" class="Table" style="border-collapse:collapse; border:none; margin-left:6px; margin-right:6px">
<tbody>
<tr>
<td style="border-bottom:1px solid black; border-left:1px solid black; border-right:1px solid black; border-top:1px solid black; height:120px; vertical-align:top; width:256px">
<p style="margin-left:40px"><span style="font-size:11pt"><span style="font-family:"Arial MT",sans-serif"><span style="font-size:9.0pt">Por</span></span></span><span style="font-size:11pt"><span style="font-family:"Arial MT",sans-serif"><span style="font-size:9.0pt"> </span></span></span><span style="font-size:11pt"><span style="font-family:"Arial MT",sans-serif"><span style="font-size:9.0pt">CORPORACION</span> <span style="font-size:9.0pt">EDUCACIONAL</span> <span style="font-size:9.0pt">BRADFORD:</span></span></span></p>
<p> </p>
<p style="margin-left:40px"><span style="font-size:11pt"><span style="font-family:"Arial MT",sans-serif"><span style="font-size:10.0pt">Rectora:</span></span></span></p>
<p style="margin-left:40px"> </p>
<p style="margin-left:40px"> </p>
<p style="margin-left:40px"><span style="font-size:11pt"><span style="font-family:"Arial MT",sans-serif"><span style="font-size:10.0pt">Presidente Directorio:</span></span></span></p>
<p style="margin-left:40px"> </p>
<p style="margin-left:40px"> </p>
<p style="margin-left:40px; margin-right:74px"> </p>
</td>
<td style="border-bottom:1px solid black; border-left:none; border-right:1px solid black; border-top:1px solid black; height:120px; vertical-align:top; width:245px">
<p> </p>
<p style="margin-left:40px"> </p>
<p style="margin-left:40px"><span style="font-size:11pt"><span style="font-family:"Arial MT",sans-serif"><span style="font-size:9.0pt">Apoderado de Cuentas: </span></span></span></p>
<p style="margin-left:7px"> </p>
</td>
</tr>
</tbody>
</table>';
}
function pre($data = [])
{
echo '<pre>';
print_r($data);
echo '</pre>';
}
function pre_die($data = [])
{
echo '<pre>';
print_r($data);
echo '</pre>';
die();
}
function getConfiguration($code)
{
$configurationRepository = new ConfigurationRepository();
$configuration = $configurationRepository->getByCode($code);
$data = $configuration->data_fields ? json_decode($configuration->data_fields, TRUE) : null;
if (empty($data)) {
return null;
}
switch ($code) {
case 'general':
return [
'whatsapp' => $data['whatsapp'] ?? null,
'email' => $data['email'] ?? null,
'cae_title' => $data['cae_title'] ?? null,
'cae_message' => $data['cae_message'] ?? null,
'cfe_title' => $data['cfe_title'] ?? null,
'cfe_message' => $data['cfe_message'] ?? null,
'inactive_title' => $data['inactive_title'] ?? null,
'inactive_message' => $data['inactive_message'] ?? null,
'enrollment_start_date' => $data['enrollment_start_date'] ?? null,
'enrollment_end_date' => $data['enrollment_end_date'] ?? null,
];
case 'contract_template':
return [
'template' => $data['template'] ?? null,
];
case 'toku':
$fields = [
'status' => $data['status'] ?? false,
'api_token' => $data['api_token'] ?? '',
'url_toku' => $data['url_toku'] ?? null,
'url_portal' => !empty($data['url_portal']) ? $data['url_portal'] . '/customer-portal?user=#PARENT_CODE' : null,
'url_portal_base' => $data['url_portal'] ?? null,
'account_code' => $data['account_code'] ?? null,
'generic_rut' => $data['generic_rut'] ?? null,
'url_pac' => null,
'url_onetime' => null,
];
if (!empty($data['url_portal']) && !empty($data['account_code'])) {
$fields['url_pac'] = $data['url_portal'] . '/recurring?accessSource=priv0&portal=0&user=#PARENT_CODE&account=' . $data['account_code'] . '&subscriptions=#SUBSCRIPTION_IDS';
$fields['url_onetime'] = $data['url_portal'] . '/onetime?accessSource=priv0&user=#PARENT_CODE&account=' . $data['account_code'] . '&invoices=#INVOICE_IDS';
}
return $fields;
case 'firmaki':
return [
'status' => $data['status'] ?? false,
'environment' => $data['environment'] ?? 'integration',
'url_sandbox' => $data['url_sandbox'] ?? 'https://api-sandbox.signapis.com',
'url_production' => $data['url_production'] ?? 'https://api.signapis.com',
'api_key' => $data['api_key'] ?? null,
'email_account' => $data['email_account'] ?? null,
'password_account' => $data['password_account'] ?? null,
];
case 'mindicador':
return [
'uf' => $data['uf'] ?? ['codigo' => 'uf', 'valor' => 0, 'fecha' => null],
];
default:
return null;
}
}
/**
* Obtiene el valor actual de la UF desde mindicador.cl con cache diario en BD.
* @return float Valor de la UF en CLP (ej: 39694.31)
*/
function getUfValue(): float
{
$config = getConfiguration('mindicador');
$uf = $config['uf'] ?? null;
// Verificar si ya tenemos el valor de hoy
if ($uf && !empty($uf['fecha']) && $uf['valor'] > 0) {
$storedDate = substr($uf['fecha'], 0, 10); // 'YYYY-MM-DD'
if ($storedDate === now()->format('Y-m-d')) {
return (float) $uf['valor'];
}
}
// Consultar mindicador.cl
try {
$response = Http::timeout(5)->get('https://mindicador.cl/api');
if ($response->successful()) {
$data = $response->json();
$ufData = $data['uf'] ?? null;
if ($ufData && isset($ufData['valor'])) {
// Guardar en BD con fecha de hoy
$ufData['fecha'] = now()->format('Y-m-d');
Configuration::where('code', 'mindicador')->update([
'data_fields' => json_encode(['uf' => $ufData]),
'updated_at' => now(),
]);
return (float) $ufData['valor'];
}
}
} catch (\Exception $e) {
// Si falla la API, retornar valor almacenado o 0
}
return (float) ($uf['valor'] ?? 0);
}
function normalizePhoneNumber(?string $phone): ?string
{
if (empty($phone)) {
return null;
}
// Eliminamos espacios, guiones y otros caracteres
$clean = preg_replace('/\D+/', '', $phone);
// Si ya viene con el prefijo +56
if (strpos($phone, '+56') === 0) {
return $phone;
}
// Si empieza con 56 (sin +), lo agregamos
if (strpos($clean, '56') === 0) {
return '+' . $clean;
}
// Si empieza con 9 (celular chileno estándar), le agregamos +56
if (strpos($clean, '9') === 0 && strlen($clean) === 9) {
return '+56' . $clean;
}
// Si empieza con 0 o 09 (a veces lo anotan así)
if (strpos($clean, '09') === 0) {
return '+56' . substr($clean, 1);
}
// Caso genérico: retornamos con +56 al inicio
return '+56' . $clean;
}
/**
* Convierte a mayúsculas, elimina tildes y deja solo letras y espacios.
*/
function normalizeOnlyText(string $text): string
{
// Quitar espacios extra al inicio y final
$text = trim($text);
// Reemplazar tildes y caracteres especiales comunes
$text = strtr($text, [
'á' => 'a',
'é' => 'e',
'í' => 'i',
'ó' => 'o',
'ú' => 'u',
'Á' => 'A',
'É' => 'E',
'Í' => 'I',
'Ó' => 'O',
'Ú' => 'U',
'ñ' => 'n',
'Ñ' => 'N',
]);
// Dejar solo letras y espacios (quita cualquier otro carácter)
$text = preg_replace('/[^A-Za-z\s]/', '', $text);
$text = trim($text);
// Convertir a mayúsculas
return strtoupper($text);
}
/**
* Ofusca un correo manteniendo parte visible del local y dominio.
* Ejemplo: correo@gmail.com → coxxxx@xxxxx.cl | coxxxx@gmail.com
*/
function obfuscateEmail(?string $email): string
{
if (empty($email) || !str_contains($email, '@')) {
return '';
}
[$local, $domain] = explode('@', $email, 2);
$local = trim($local);
$domain = trim($domain);
if (strlen($local) <= 2) {
return str_repeat('x', strlen($local)) . '@' . $domain;
}
// Mostrar las 2 primeras letras y ofuscar el resto hasta 6 caracteres
$visible = substr($local, 0, 2);
$maskedLength = min(strlen($local) - 2, 6);
$masked = str_repeat('x', $maskedLength);
return strtolower($visible . $masked . '@' . $domain);
}