2

我正在将 C# 函数复制到 PHP。在 C# 中,GUID、DateTime 和布尔值被转换为字节。接下来,字节数组被合并和编码。最后一步是将其转换为 base64。

字节数组存在以下部分:

GUID: 16 bytes
Timestamp: 8 bytes
Boolean: 1 byte

在 php 中,我已经转换了 base64 并将字符串解码回字节。我还设法将前 16 个字节转换为 GUID。我验证了 PHP 返回给我的字节,它们是正确的。

现在我将 8 个字节转换为 PHP 中的时间戳。到目前为止,我没有运气。我想问题是它返回一个int64。

C#

这是 C# 字节数组到日期时间转换:

public DateTime Timestamp;
......
byte[] timestamp_bytes = new byte[8];
input.Read(timestamp_bytes, 0, 8);
Timestamp = DateTime.FromBinary(System.BitConverter.ToInt64(timestamp_bytes, 0));

这是 C# 日期时间到字节数组的转换:

public DateTime Timestamp;
......
byte[] timestamp_bytes = System.BitConverter.GetBytes(Timestamp.ToBinary());

当我输出 Timestamp.ToString() 时,在这两种情况下我都会得到23-12-2011 09:54:56

PHP

在 PHP 中,我设法获得了 8 个字节的十六进制:

$bin = pack("C*", 119, 23, 124, 173, 103, 143, 206, 136);
$hex = unpack("H*", $bin);

接下来我该怎么办?我已经尝试了一些转换方法,但我似乎从来没有得到正确的答案。

附加信息:

这8个字节分别是:119、23、124、173、103、143、206、136

十六进制字符串为:77177cad678fce88

我应该得到的日期时间:23-12-2011 09:54:56

php -r '回显 PHP_INT_MAX;' 返回 9223372036854775807

C# 应用程序不在我的权限范围内,所以我不能保证我可以更改它

4

3 回答 3

0

为此,您需要在 C# 中转换为 unix 时间戳,并将此数据打包成二进制而不是 8 字节 DateTime 对象序列化。直到 2038 年,4 个字节就足够了。

从这里借用(或偷窃?),这是您可以在 C# 中创建 Unix 时间戳的方法:

public DateTime timestamp;
// ......
byte[] timestamp_bytes = new byte[8];
input.Read(timestamp_bytes, 0, 8);
timestamp = DateTime.FromBinary(System.BitConverter.ToInt64(timestamp_bytes, 0));

TimeSpan diff = (Timestamp - new DateTime(1970, 1, 1).toLocalTime());
int unix = (int) diff.TotalSeconds;
// unix is now a signed 32 bit integer representing the Unix timestamp in a way
// that PHP will understand

然后在 PHP 中,您可以将 4 个二进制字节转换回表示 unix 时间戳的整数,如下所示:

$timestamp = unpack('N', $binaryString);
echo date('d-m-Y H:i:s', $timestamp); // Should give 23-12-2011 09:54:56
于 2012-05-15T09:05:41.560 回答
0

让我们看一下DateTime.ToBinary 方法DateTime.Ticks 属性文档。

首先,DateTime的二进制形式表示两个属性(Kind 和 Ticks),不清楚它们在二进制字符串中是如何连接的。那么,Ticks属性是自耶稣基督诞生以来经过的百万分之一秒的数字。

那么,如何进行呢?

  1. 尝试了解KindTicks属性是如何二进制存储的。我们需要蜱虫。我的建议是尝试将一些典型的 DateTime 值转换为二进制并分析输出。从DateTime.MinValue开始,应该对应于01-01-0001 00:00:00. 您应该看到(我认为)所有零,除了Kind值(如果存在)。

  2. 一旦有了 64 位的Ticks值,就可以使用floor($ticks / 10000000). 最后,您必须减去从 1 年到 1970 年(Unix 标准)所经过的秒数,这是一个常数,您可以将 C# DateTime 转换01-01-1970 00:00:00为二进制...

祝你好运。

于 2012-05-15T08:50:48.547 回答
0

我最终得到了这个,其中解密的是解密令牌后的字符串。

        $byte_array = array_slice(unpack("C*", "\0" . $decrypted), 1);

        $timestamp_array = array_slice($byte_array, 0, 8);
        $guid_array = array_slice($byte_array, 8, 16);
        $is_read_only_array = array_slice($byte_array, 24, 1);

        // CONVERT GUID
        .....

        // CONVERT TIMESTAMP
        $timestamp_hex = "";
        foreach ($timestamp_array as $byte) {
            $timestamp_hex .= pack("C*", $byte);
        }
        $timestamp = hexdec($timestamp_hex);

        // CONVERT IS READ ONLY
        ....
于 2013-08-04T17:17:02.547 回答