It is very common for extensions to need access to the user's IP address. I see extensions doing silly things like this:
$ip = $_SERVER['REMOTE_ADDR']; $ip = $this->input->server->get('REMOTE_ADDR');
DO NOT DO THAT; THIS IS WRONG ON MANY LEVELS!
The first line tries to access the $_SERVER superglobal which, as mentioned in the previous section, is a security issue waiting to happen.
Both of these lines make a wrong assumption: that the REMOTE_ADDR key of the server superglobal array will contain the user's IP address. This is not true if the server is behind a load balancer, CDN, firewall or any other kind of non-transparent proxy. In these cases a different HTTP header —typically X-Forwarded-For— may be used to convey the forwarding chain of IP addresses. However, you should NOT attempt to read this header yourself for two reasons. First of all, if the site is not behind a non-transparent proxy a malicious actor can send a forged X-Forwarded-For header to trick your extension into believing the request came from a different IP address than the one it actually originates. Second, this header may contain more than one IP address in a comma-separated list. Validating, sanitizing and parsing that list is tricky and may lead to some very bad times and security issues.
Joomla 3.10 and later (including all 4.x releases and beyond) include a fork of my IPHelper class which deals with all of these details automatically. They also expose user-facing options in the Global Configuration so that the site owner can inform Joomla whether their site is behind a non-transparent proxy server.
You can get the real IP address of the user with this:
$ip = \Joomla\Utilities\IpHelper::getIp();
Even better, going through the IpHelper makes your code testable. Your unit tests can simply call:
\Joomla\Utilities\IpHelper::setIp('1.2.3.4');
to set a fake IP address of your choice (IPv4 or IPv6).
Finally, IpHelper has two more handy methods:
isIPv6
which tells you if you are dealing with
an IPv6 address and IPinList
which lets you
figure out if an IP address is contained in an array which consists of
any combination of IPv4/IPv6 addresses, IPv4 ranges (e.g.
1.2.3.4-1.2.3.255), IPv4/IPv6 subnets in CIDR notation (e.g. 1.2.3.4/24)
or IPv4 subnets in IP/Netmask notation (e.g. 192.168.1.0/255.255.255.0).
Since many use cases for getting the user's IP address ultimately come
down to checking if it belongs in a range of IP addresses or a list of
allowed/blocked IP addresses you'll find the latter method extremely
handy. I went through the pain of figuring out IP address maths and
Joomla included my work in the core so you don't have to deal with it
yourself!