338 words, 2 min read

When building SaaS applications, it is common to treat internal (private or reserved) IP addresses differently from public ones. Typical examples are rate limiting, audit logging, or skipping geo-IP lookups for localhost traffic.

This post shows how to check whether an IP address is internal, starting from an Elixir example and then translating the same idea to PHP.

The Elixir way

In Elixir, the standard library provides :inet.parse_address/1 to validate IP addresses. From there, you can pattern match on the octets to exclude private and reserved ranges.

defmodule IPUtils do
def public_ipv4?(ip) when is_binary(ip) do
case :inet.parse_address(String.to_charlist(ip)) do
{:ok, {a, b, _c, _d}} ->
not private_or_reserved?(a, b)
_ ->
false
end
end
defp private_or_reserved?(10, _), do: true
defp private_or_reserved?(127, _), do: true
defp private_or_reserved?(192, 168), do: true
defp private_or_reserved?(172, b) when b >= 16 and b <= 31, do: true
defp private_or_reserved?(_, _), do: false
end
IPUtils.public_ipv4?("127.0.0.1") # false
IPUtils.public_ipv4?("8.8.8.8") # true

Pattern matching keeps the intent clear and makes it easy to extend this logic later if you want to support IPv6 or additional ranges.

The PHP approach

PHP ships with a very convenient helper: filter_var. Combined with the right flags, it allows you to validate only public IPv4 addresses.

$user_ip = '127.0.0.1';
$is_public = filter_var($user_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
if ($is_public === false) {
// Internal, private, or reserved IP
} else {
// Public IPv4 address
}

What this does:

  • FILTER_VALIDATE_IP checks that the value is a valid IP address.
  • FILTER_FLAG_IPV4 restricts the check to IPv4.
  • FILTER_FLAG_NO_PRIV_RANGE excludes private ranges such as 10.0.0.0/8 and 192.168.0.0/16.
  • FILTER_FLAG_NO_RES_RANGE excludes reserved ranges like 127.0.0.0/8.

If the function returns false, the IP is either invalid or internal/reserved.

Closing thoughts

PHP’s filter_var is hard to beat for conciseness, but the same idea translates cleanly to other ecosystems:

  • Validate the IP address first.
  • Explicitly exclude private and reserved ranges.
  • Treat everything else as public.

Keeping this logic centralized (for example in a small utility module) helps ensure consistent behavior across your application, regardless of the language you are using.