export function inet_pton(a: string): string | false { // discuss at: https://locutus.io/php/inet_pton/ // parity verified: PHP 8.3 // original by: Theriault (https://github.com/Theriault) // improved by: alromh87 and JamieSlome // example 1: inet_pton('::') // returns 1: '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' // example 2: inet_pton('127.0.0.1') // returns 2: '\x7F\x00\x00\x01' const f = String.fromCharCode // IPv4 const ipv4Match = a.match(/^(?:\d{1,3}(?:\.|$)){4}/) if (ipv4Match) { const octets = ipv4Match[0] .split('.') .slice(0, 4) .map((part) => Number.parseInt(part, 10)) const [a0, a1, a2, a3] = octets if ( a0 === undefined || a1 === undefined || a2 === undefined || a3 === undefined || octets.some((octet) => Number.isNaN(octet) || octet < 0 || octet > 255) ) { return false } const packed = f(a0, a1, a2, a3) // Return if 4 bytes, otherwise false. return packed.length === 4 ? packed : false } // IPv6 if (a.length > 39) { return false } const segments = a.split('::') if (segments.length > 2) { return false } // :: can't be used more than once in IPv6. const reHexDigits = /^[\da-f]{1,4}$/i const packedSegments: string[] = [] for (const segment of segments) { if (segment.length === 0) { packedSegments.push('') continue } const hextets = segment.split(':') let packed = '' for (const hextetSource of hextets) { const hextet = hextetSource // check if valid hex string up to 4 chars if (!reHexDigits.test(hextet)) { return false } const parsedHextet = parseInt(hextet, 16) // Would be NaN if it was blank, return false. if (Number.isNaN(parsedHextet)) { // Invalid IP. return false } packed += f(parsedHextet >> 8, parsedHextet & 0xff) } packedSegments.push(packed) } const bytesLength = packedSegments.reduce((total, part) => total + part.length, 0) if (bytesLength > 16) { return false } if (segments.length === 1 && bytesLength !== 16) { return false } return packedSegments.join('\x00'.repeat(16 - bytesLength)) }