Cargando…

Esto está tardando más de lo esperado.

Volver al centro de ayuda

Detecta el país del visitante

De dónde sale el país de un visitante, dónde se guarda y qué lo lee.

El kit deduce el país de cada visitante a partir de su IP, lo recuerda y se lo entrega a las funciones que ponen precio, dan formato o ubican algo por país. Esta guía cubre el servicio que lo hace, las dos variables de entorno que lee, dónde se guarda el resultado para un visitante y para una cuenta, qué lo usa, y qué pasa en tu máquina, donde no hay IP pública.

El servicio

App\Services\CountryDetectionService es una clase de métodos estáticos y el único punto de entrada. Llámala desde cualquier lugar:

use App\Services\CountryDetectionService;

$country = CountryDetectionService::detect(); // 'MX', o null

detect()

Devuelve un código ISO de dos letras, o null cuando nada respondió. Intenta, en orden:

  1. El country_code de la cuenta con sesión iniciada, cuando lo tiene.
  2. Un código ya encontrado para este visitante, guardado en la sesión bajo current_country_code.
  3. La IP de la petición, a través de detectFromIp(). Un código encontrado así se escribe en la sesión, para que la consulta ocurra a lo más una vez por visita.

detectFromIp(?string $ip)

La consulta de bajo nivel, usable también por sí sola:

  • Sin IP devuelve null.
  • Una IP privada o reservada (127.0.0.1, ::1, 10.x, 192.168.x y similares) devuelve config('app.country_code_fallback'), o null cuando está vacía. No se hace ninguna petición.
  • Cualquier otra IP se envía a https://ipapi.co/{ip}/country/, sin llave y con un tiempo de espera de dos segundos. Una respuesta de dos letras se devuelve en mayúsculas; una falla, un tiempo agotado o cualquier otra cosa devuelve null.

La aplicación confía en todos los proxies, así que detrás de un balanceador la IP es la de X-Forwarded-For y no la del balanceador.

getWorldId()

Resuelve el código detectado al id numérico del país en Weblabor World, a través de GET https://world.weblabor.mx/api/country/{codigo} con el token como encabezado Bearer y un tiempo de espera de dos segundos. Sin WEBLABOR_WORLD_TOKEN no devuelve nada y no hace petición; ante cualquier error falla en silencio.

detectTimezone() y worldTimezone()

La misma clase encuentra la zona horaria del visitante, desde la sesión, desde https://ipapi.co/{ip}/timezone/, y por último desde la zona horaria del país en Weblabor World cuando el token está puesto. Ese flujo está en Zonas horarias y fechas.

Las dos variables de entorno

Variable Clave de configuración Valor por omisión Qué hace
COUNTRY_CODE_FALLBACK app.country_code_fallback US El país que se asume cuando la IP es privada. Ponla en tu mercado para el desarrollo local, o en un valor vacío para obtener null y ver lo que ve un visitante sin país.
WEBLABOR_WORLD_TOKEN services.weblabor.world.token vacío El token de la API de Weblabor World. Con él, una cuenta guarda además su país como división de World, los selects de país, estado y ciudad del perfil cargan sus opciones, y el respaldo de zona horaria por país está disponible. Sin él, la detección sigue funcionando sólo con la IP.

.env.example lista WEBLABOR_WORLD_TOKEN= y no COUNTRY_CODE_FALLBACK; agrega esta última cuando US no sea el país para el que desarrollas.

El paquete World UI que dibuja los selects lee el mismo token, más WEBLABOR_WORLD_ENDPOINT, cuyo valor por omisión es https://world.weblabor.mx/api y sólo cambia cuando Weblabor te lo indique.

Dónde se guarda el país

Para un visitante, en la sesión, bajo current_country_code. Se escribe la primera vez que detect() llega a la consulta por IP y se lee en cada llamada posterior, así que un visitante que se mueve entre páginas se consulta una sola vez.

Para una cuenta, en users.country_code, una columna anulable de dos caracteres. Se llena cuando se crea la cuenta: App\Observers\UserObserver llama a detect() después de la inserción, que en ese momento lee la sesión con la que la persona se registró. Nunca se vuelve a detectar después; una cuenta conserva su país hasta que lo cambia.

Con WEBLABOR_WORLD_TOKEN puesto, el observer guarda además el id de división de World en extra_data.country. Ese atributo tiene el cast DivisionCast, así que leerlo devuelve un objeto Division cuyo ->country es el código ISO. El "Selecciona país" del perfil está ligado a ese atributo; cuando la persona elige otro país ahí, el observer copia el nuevo código ISO de vuelta a country_code, para que los dos nunca discrepen. Sin el token, extra_data.country no se toca y sólo se escribe country_code.

Qué lee el país

Función Cómo
Precios por país El paquete de cobro le pregunta a CountryDetectionService a través del country_resolver de config/billing-core.php. El bloque de precios de la landing, la página de planes y la suscripción automática al plan gratuito al registrarse muestran la fila de precio del país del visitante y caen a la fila default. Una fila de precio lleva su propia moneda, así que el país decide en qué moneda se cobra a la persona. Revisa Crea y da precio a un plan.
Números de teléfono normalize_phone_number() convierte un número escrito sin + a E.164 asumiendo el country_code de la cuenta, el país detectado o COUNTRY_CODE_FALLBACK, en ese orden. User::phoneExists() lo usa para encontrar un número guardado con otra forma.
El dashboard de administración La métrica "Usuarios por país" agrupa las cuentas por country_code, con unknown para las que no tienen.
Dispositivos conectados La lista de dispositivos en /account llama a detectFromIp() con la IP de cada sesión y nombra el país a través de la lista de países de World.
La zona horaria de la cuenta Cuando la IP no da zona horaria, se usa la del país desde Weblabor World, como se describe arriba.

El campo de teléfono en sí no preselecciona un prefijo a partir del país: la persona escribe el número con su código de país, y la normalización de arriba es lo que interpreta un número escrito sin él.

Desarrollo local

En tu máquina toda petición llega desde 127.0.0.1 o ::1, que es una IP reservada, así que detectFromIp() nunca llama a ipapi.co y devuelve COUNTRY_CODE_FALLBACK en su lugar. Con el valor por omisión eres un visitante de Estados Unidos; pon COUNTRY_CODE_FALLBACK=MX para ver precios mexicanos, o déjala vacía para obtener null y la fila de precio default. El valor se lee en el primer detect() de una visita y se guarda en la sesión, así que después de cambiarlo cierra sesión o abre una ventana privada.

Todo lo que le pregunta a Weblabor World, el id de división, los selects de país, estado y ciudad del perfil, los nombres de país en la lista de dispositivos y la zona horaria por país, necesita WEBLABOR_WORLD_TOKEN también en tu máquina. Los métodos del servicio fallan en silencio sin él; los selects no tienen API de dónde cargar sus opciones. La detección por IP en sí no necesita el token.