WordPress REST API如何自定义端点来接收XML文件

不能。WordPress REST API 默认不支持application/xml,需手动注册端点读取php://input并解析XML,注意Content-Type校验、空白处理、异常捕获及数据过滤。

WordPress REST API 能否直接接收 XML 文件?

不能。WordPress REST API 默认只接受 application/json 或表单编码(application/x-www-form-urlencodedmultipart/form-data)的请求体,application/xml 不在默认解析支持范围内。即使你用 curl 发送 XML,$_POST$_REQUEST 仍为空,file_get_contents('php://input') 才是唯一可靠入口。

如何注册一个能读取原始 XML 的自定义 REST 端点?

必须绕过 WordPress 的默认参数解析逻辑,手动读取原始请求体,并在回调函数中解析 XML。关键点:注册端点时设 methodsWP_REST_Server::CREATABLE,禁用 args 参数校验(否则会因无法匹配 JSON schema 报错),并在回调里用 file_get_contents('php://input') 拿到原始字节。

  • register_rest_route()args 数组不要定义任何参数字段,否则 REST 服务器会尝试自动解析并失败
  • 务必检查 Content-Type 请求头是否为 application/xmltext/xml,避免误处理其他类型
  • 使用 simplexml_load_string() 解析前,先用 trim() 去除空白,否则空字符串会导致警告
  • 捕获 SimpleXMLElement 构造异常,返回有意义的 WP_Error
register_rest_route('myplugin/v1', '/upload-xml', array(
  'methods' => WP_REST_Server::CREATABLE,
  'callback' => function( $request ) {
    $raw_body = file_get_contents('php://input');
    if ( ! $raw_body ) {
      return new WP_Error('empty_body', 'No XML data received', array('status' => 400));
    }

    $content_type = $request->get_header('Content-Type');
    if ( false === stripos($content_type, 'application/xml') && false === stripos($content_type, 'text/xml') ) {
      return new WP_Error('invalid_content_type', 'Content-Type must be application/xml or text/xml', array('status' => 400));
    }

    $xml = simplexml_load_string(trim($raw_body));
    if ( false === $xml ) {
      return new WP_Error('invalid_xml', 'Failed to parse XML', array('status' => 400));
    }

    // 此处处理 $xml 对象,例如:$xml->item->__toString()
    return rest_ensure_response(array('status' => 'success', 'parsed' => true));
  },
  'permission_callback' => '__return_true', // 实际使用请替换为真实权限检查
));

XML 解析后如何安全提取数据并存入数据库?

不要直接将 SimpleXMLElement 对象传给 $wpdb->insert()wp_insert_post()。XML 节点名可能含非法字符,文本值可能含未转义 HTML 或恶意脚本。必须显式遍历、过滤、验证每个字段。

  • (string) $xml->field_name 强制转为字符串,避免对象残留
  • 对用户输入字段(如标题、内容)使用 wp_kses_post()sanitize_text_field(),而非 esc_html()(后者是输出函数)
  • 数值字段用 absint()floatval() 显式转换,防止字符串注入
  • 如果 XML 含嵌套结构(如 ...),需用 foreach( $xml->items->item as $item ) 遍历,不能假设只有一项

为什么用 multipart/form-data 上传 XML 文件更稳妥?

直接 POST XML 字符串容易因编码(如 UTF-8 BOM)、换行符、特殊字符(, &)导致解析失败;而用文件上传方式,XML 作为二进制附件传输,服务端从 $_FILES 读取,规避了 HTTP 主体解析问题。此时端点应接受 multipart/form-data,并用 move_uploaded_file() 临时保存再解析。

  • 前端用 FormData.append('xml_file', fileInput.files[0]) 提交
  • 后端检查 $_FILES['xml_file']['error'] === UPLOAD_ERR_OK 再处理
  • 临时文件路径用 $_FILES['xml_file']['tmp_name'],解析完立即 unlink()
  • 务必限制 $_FILES['xml_file']['size'](如 ≤ 2MB),防止 DoS

真正麻烦的不是注册端点,而是 XML 的编码一致性、实体转义、命名空间处理和错误定位——这些全得自己兜底,REST API 不提供 XML Schema 验证或自动映射。