cffunction/cfargument 通过 unsigned int32

cffunction/cfargument pass unsigned int32

我正在构建一个将无符号 int32 转换为 ipv4 地址的函数,在我测试该范围的上半部分之前,它一切正常。

<cffunction name="Int32ToIPv4" returntype="string" output="false" access="public" hint="returns IPv4 address for int32 number">
    <cfargument name="nInt32" type="numeric" required="yes" hint="int32 to convert to ipv4 address">

    <cfreturn
        bitAnd((arguments.nInt32 / 16777216), 255) & "."
        & bitAnd((arguments.nInt32 / 65536), 255) & "."
        & bitAnd((arguments.nInt32 / 256), 255) & "."
        & bitAnd(arguments.nInt32, 255)
    >
</cffunction>

ColdFusion 似乎将 type="numeric" 解释为 signed 32 位整数。

这个例子有效:

Int32ToIPv4(nInt32 = 1181772947) = #Int32ToIPv4(nInt32 = 1181772947)# (expected value = 70.112.108.147)<br>

这个例子失败了:

Int32ToIPv4(nInt32 = 3401190660) = #Int32ToIPv4(nInt32 = 3401190660)# (expected value = 202.186.13.4)<br>

错误信息是:"Cannot convert the value 3.40119066E9 to an integer because it cannot fit inside an integer."

我是否必须将此数字作为字符串传递并在使用前将其转换为 Java unsigned int?

我想在某个时候对 ipv6 地址(无符号 128 位整数)做一些类似的事情。对于此类数据类型的任何建议,我们将不胜感激。

实际上是bitAnd()施加了32位整数限制,而不是cfargument。

有趣的是,如果您分别检查每个计算,前三 (3) 个计算结果很好。由于除法,传递给 bitAnd() 的值实际上足够小,可以放入 INT 中。但是,最后一个使用了明显太大的原始值,这就是导致这个特定数字错误的原因。

 bitAnd(  (3401190660 / 16777216), 255 )  // Actual => 202.7267611032, 255
 bitAnd(  (3401190660 / 65536), 255 ) // Actual => 51898.05084233, 255
 bitAnd(  (3401190660 / 256), 255 )  // Actual =>13285901.0156, 255
 bitAnd(3401190660, 255) // Too big!

由于 CF 中的大多数相关数学函数仅限于 32 位整数,我不确定是否(或有多简单)仅使用 CF 就可以完成。假设您使用的是 Java 8+,您还可以访问新的未签名方法,例如 Integer.parseUnsignedInt(String)

我个人认为这将是一个很好的学习练习。但是,除非您非常熟悉签名与未签名的细节以及它与 IP4 和 IP6 地址的关系,否则您可能只想使用现有的 java 库来避免常见的陷阱。如Guava's InetAdress:

// IP4
input = 3401190660;
uint = createObject("java", "java.lang.Integer").parseUnsignedInt(input);
inet = createObject("Java", "com.google.common.net.InetAddresses");
result = inet.fromInteger(uint).getHostAddress();

我确实想出了一个本机 Java 解决方案,该解决方案涉及传递​​一个无符号的 32 位 int。所以,@Leigh 关于 cfargument 正常工作是正确的。

<cffunction name="UInt32ToIPv4" returntype="string" output="no" access="public" hint="returns IPv4 address for uint32 number">
    <cfargument name="nUInt32" type="numeric" required="yes" hint="uint32 to convert to ipv4 address">

    <cfset local['JavaLangInteger'] = CreateObject("java", "java.lang.Integer")>
    <cfset local['JavaMathBigInteger'] = CreateObject("java", "java.math.BigInteger")>
    <cfset local['JavaNetInetAddress'] = CreateObject("java", "java.net.InetAddress")>

    <cfif arguments.nUInt32 EQ 0>
        <cfreturn "">
    </cfif>

    <cftry>
        <cfset local['vcIPv4'] = local.JavaNetInetAddress.getByAddress(local.JavaMathBigInteger.valueOf(local.JavaLangInteger.parseUnsignedInt(arguments.nUInt32)).toByteArray())>
        <cfreturn reReplace(local.vcIPv4, "[^0-9\.]", "", "all")>
        <cfcatch type="any">
            <cfreturn "">
        </cfcatch>
    </cftry>
</cffunction>

让我知道这个解决方案是否有任何问题,因为我认为我会使用它而不是 public java 库。

我已经为 ipv6 编写了函数来处理转换 (unsigned 128-bit int to/from ipv6)。不确定是否对这些功能感兴趣。如果有,我将使用该代码创建单独的 questions/answers。