在 PHP 中获取 IP 地址通常都是来自 $_SERVER
全局变量中,比如
$_SERVER['HTTP_CLIENT_IP'];
// OR
$_SERVER['HTTP_X_FORWARDED_FOR'];
// OR
$_SERVER['HTTP_X_REAL_IP']; // 更多自定义的 key
// OR
$_SERVER['REMOTE_ADDR'];
也有可能在被前端 Web server 或 load balance 附加到请求头上,如 nginx 中可能设置了
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
根据上面的逻辑,我简单实现了如下的一个方法
// azalea.h
PHP_FUNCTION(azalea_ip);
// azalea.c
/* {{{ azalea_getmodel
*/
PHP_FUNCTION(azalea_ip)
{
zval *server, *field;
zend_string *ip = NULL;
server = zend_hash_str_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER") - 1);
if (Z_TYPE_P(server) == IS_ARRAY) {
if ((field= zend_hash_str_find(Z_ARRVAL_P(server), "HTTP_CLIENT_IP", sizeof("HTTP_CLIENT_IP") - 1)) &&
Z_TYPE_P(field) == IS_STRING) {
ip = Z_STR_P(field);
} else if ((field = zend_hash_str_find(Z_ARRVAL_P(server), "HTTP_X_FORWARDED_FOR", sizeof("HTTP_X_FORWARDED_FOR") - 1)) &&
Z_TYPE_P(field) == IS_STRING) {
ip = Z_STR_P(field);
} else if ((field = zend_hash_str_find(Z_ARRVAL_P(server), "REMOTE_ADDR", sizeof("REMOTE_ADDR") - 1)) &&
Z_TYPE_P(field) == IS_STRING) {
ip = Z_STR_P(field);
}
}
if (ip) {
zend_string_copy(ip);
} else {
ip = zend_string_init("0.0.0.0", sizeof("0.0.0.0") - 1, 0); // 默认值
}
RETURN_STR(ip);
}
/* }}} */
当然了,PHP 通过 $_SERVER
甚至 request header 来获取 IP 都不是绝对靠谱的方法,还得看架构和运行环境。