WordPress.org

Making WordPress.org

Ticket #2823: 2823-ipv6.1.diff

File 2823-ipv6.1.diff, 3.1 KB (added by coreymckrill, 4 years ago)
  • 1.0/index.php

    diff --git 1.0/index.php 1.0/index.php
    index acc1871..416dfd6 100644
    function get_prepare_placeholders( $number, $format ) { 
    361361 * NOTE: The location that is found here cannot be returned to the client.
    362362 *       See `rebuild_location_from_geonames()`.
    363363 *
    364  * @todo - Add support for IPv6 addresses. Otherwise, this will quickly lose effectiveness. As of March 2017, IPv6
    365  *         adoption is at 16% globally and rising relatively fast. Some countries are as high as 30%.
    366  *         See https://www.google.com/intl/en/ipv6/statistics.html#tab=ipv6-adoption for current stats.
    367  *
    368  * @todo - Core sends anonymized IPs like `2a03:2880:2110:df07::`, so make sure those work when implementing IPv6
    369  *
    370364 * @param string $dotted_ip
    371365 *
    372366 * @return null|object `null` on failure; an object on success
    function get_prepare_placeholders( $number, $format ) { 
    374368function guess_location_from_ip( $dotted_ip ) {
    375369        global $wpdb;
    376370
    377         $long_ip = ip2long( $dotted_ip );
    378         if ( $long_ip === false )
     371        $long_ip = false;
     372
     373        if ( filter_var( $dotted_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
     374                $long_ip = ip2long( $dotted_ip );
     375                $from    = 'ip2location';
     376                $where   = 'ip_to >= %d';
     377        } else if ( filter_var( $dotted_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
     378                $long_ip = _ip2long_v6( $dotted_ip );
     379                $from    = 'ip2location_v6';
     380                $where   = "ip_to >= CAST('%s' AS decimal(39,0))";
     381        }
     382
     383        if ( false === $long_ip || ! isset( $from, $where ) ) {
    379384                return;
     385        }
    380386
    381387        $row = $wpdb->get_row( $wpdb->prepare( "
    382388                SELECT ip_city, ip_latitude, ip_longitude, country_short
    383                 FROM ip2location
    384                 WHERE ip_to >= %d
     389                FROM $from
     390                WHERE $where
    385391                ORDER BY ip_to ASC
    386392                LIMIT 1",
    387393                $long_ip
    function guess_location_from_ip( $dotted_ip ) { 
    396402}
    397403
    398404/**
     405 * Convert an IPv6 address to an IP number than can be queried in the ip2location database.
     406 *
     407 * PHP doesn't handle integers large enough to accommodate IPv6 numbers (128 bit), so the number needs
     408 * to be cast as a string.
     409 *
     410 * @link https://en.wikipedia.org/wiki/IPv6
     411 * @link http://php.net/manual/en/language.types.integer.php
     412 *
     413 * The code in this function is based on an answer here: http://lite.ip2location.com/faqs
     414 *
     415 * Uses `inet_pton()` which correctly parses truncated IPv6 addresses such as `2a03:2880:2110:df07::`
     416 *
     417 * @access private
     418 *
     419 * @param string $address The IPv6 address to convert.
     420 *
     421 * @return string|bool `false` if invalid address. Otherwise an IP number cast as a string.
     422 */
     423function _ip2long_v6( $address ) {
     424        $int = inet_pton( $address );
     425
     426        if ( false === $int ) {
     427                return false;
     428        }
     429
     430        $bits     = 15;
     431        $ipv6long = 0;
     432
     433        while ( $bits >= 0 ) {
     434                $bin = sprintf( "%08b", ( ord( $int[ $bits ] ) ) );
     435
     436                if ( $ipv6long ) {
     437                        $ipv6long = $bin . $ipv6long;
     438                } else {
     439                        $ipv6long = $bin;
     440                }
     441
     442                $bits--;
     443        }
     444
     445        $ipv6long = gmp_strval( gmp_init( $ipv6long, 2 ), 10 );
     446
     447        return $ipv6long;
     448}
     449
     450/**
    399451 * Rebuild the location given to the client from the event source data
    400452 *
    401453 * We cannot publicly expose location data that we retrieve from the `ip2location` database, because that would