EPP 不像你想象的那样工作。首先,我建议您花一些时间详细阅读 RFC5730 和 5734,它们将在下面讨论。完成这项工作后,您将需要全面掌握 RFC 5731 5732 和 5733 中的所有 EPP 详细信息。不要期望在没有阅读所有内容的情况下编写成功的 EPP 客户端。
现在回到您的问题,以及为什么您不遵循 EPP 规范。
请参阅 RFC5730 的第 2 节,在此处转载:
|
V
+-----------------+ +-----------------+
| Waiting for | Connected | Prepare |
| Client |----------------->| Greeting |
+-----------------+ or <hello> +-----------------+
^ |
| Close Connection Send |
| or Idle Greeting |
+-----------------+ V
| End | Timeout +-----------------+
| Session |<-----------------| Waiting for |
+-----------------+ | Client |
^ ^ ^ Send +-------->| Authentication |
| | | Response | +-----------------+
| | | +--------------+ |
| | | | Prepare Fail | | <login>
| | +-----| Response | | Received
| | Send +--------------+ V
| | 2501 ^ +-----------------+
| | Response | | Processing |
| | +---------| <login> |
| | Auth Fail +-----------------+
| | Timeout |
| +-------------------------------+ | Auth OK
| | V
| +-----------------+ <hello> +-----------------+
| | Prepare |<----------| Waiting for |
| | Greeting |---------->| Command or |
| +-----------------+ Send | <hello> |
| Send x5xx Greeting +-----------------+
| Response +-----------------+ Send ^ |
+-----------| Prepare | Response | | Command
| Response |----------+ | Received
+-----------------+ V
^ +-----------------+
Command | | Processing |
Processed +----------| Command |
+-----------------+
这里不同的是你的客户应该如何表现:
- 建立 TLS 连接(绝对确保验证远程证书)
- 服务器首先说话,带有问候消息(参见同一 RFC 的第 2.4 节)
- 您需要阅读此消息,并从中提取各个部分,特别是 objURI 和 extURI 部分
- 现在客户端发送其登录消息(第 2.9.1.1 节)
- 此命令与其他命令一样,将使服务器回复一个结果,告诉您它是成功(代码 1000)还是失败(任何以 2 开头的代码)
您的程序中的错误是您的客户端先说话,向服务器发送一些东西。根据上述状态模式,这是不允许的,因此请先阅读服务器回复。
因此,您的问题不在于发送 XML(虽然您对此也有问题,请参见下文),首先它不尊重谁先发言的顺序。
也不要这样做:
while (!feof($ch)) {
$data .= fread($ch, 1024);
}
请参阅解释 EPP 如何传输的 RFC 5734。总结一下并回复上面关于您的问题的一些评论:
- EPP 使用 TLS 作为传输,没有 HTTPS
- 700 是 IANA 分配的标准联系端口,除非注册管理机构另有说明
- 每个 XML 消息(在 UTF-8 序列化等之后)在线路上以 4 个字节为前缀,表示完整 EPP 帧的长度(帧 = 4 字节长度的标头 + 完整消息)。
因此,当您期望来自服务器的消息时,您会这样做:
- 您读取了前 4 个字节(这甚至可能不是那么简单,您可能需要一个一个地读取它们并将它们重新整理在一起,很大程度上取决于用于网络 I/O 的工具)
- 现在您确切地知道接下来要到达的大小,它是上述 4 个字节(正确解码)中的长度减去 4 以从全长中删除 4 个字节本身。
但请注意,当您向服务器发送内容时,您也需要这样做!不要只发送 XML 内容,您需要形成一个适当的 EPP 框架,这意味着:
- 计算消息的大小(以字节为单位,而不是以字符为单位,因此在 UTF-8 序列化等之后)
- 准备 4 个字节以将该大小存储为网络字节顺序
- 立即发送这 4 个字节,然后是 XML 消息。
此外,作为行业中的“老手”(已经在那里工作了 20 年,编写过 EPP 服务器、客户端,并参与了定义它的 RFC),请从经验中吸取这个建议:如果你的工作是连接只需要一个注册表,那么生活就简单了;您甚至可以使用注册表提供的工具包,只要它使用您选择的语言即可。
但是,一旦您需要编写一个能够正确连接到多个注册表的客户端,您就会遭受痛苦。即使它是一个标准,您也会发现注册管理机构之间存在很多差异,在许多主题上,例如如何报告扩展错误数据、存在哪些 EPP 扩展以及它们如何工作、域的响应内容:检查等等,小差异的列表很长,无法在此处列举。
由于上述所有原因,您可能也不希望重新发明轮子。有些库可以为您完成所有 EPP 工作,例如https://github.com/centralnic/php-epp
我不以任何方式认可它,因为我不知道它,因为我不使用 PHP,但也许它可以帮助您,要么按原样重复使用,这样您就无需编写代码,或者至少看看它以了解它们如何解决特定问题,以便您受到启发。
例如,关于每个 EPP 帧开头的长度和 4 个字节的上述问题,getFrame
请sendFrame
参见https://github.com/centralnic/php-epp/blob/master/Net/EPP/Protocol.php