Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/244.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用PHP跳过XML文件中的无效字符_Php_Xml_Utf 8 - Fatal编程技术网

如何使用PHP跳过XML文件中的无效字符

如何使用PHP跳过XML文件中的无效字符,php,xml,utf-8,Php,Xml,Utf 8,我试图使用PHP解析XML文件,但收到一条错误消息: 分析器错误:字符0x0超出了中允许的范围 我认为这是因为XML的内容,我认为有一个特殊的符号“☆", 我能做些什么来修复它 我还得到: 分析器错误:标记项行中的数据过早结束 是什么导致了这个错误 我正在使用 更新: 我试图找到错误行并将其内容粘贴为单个xml文件,它可以工作!!因此我仍然无法找出导致xml文件解析失败的原因。PS这是一个超过100米的大型xml文件,它会导致解析错误吗?您是否可以控制xml?如果可以,请确保数据包含在。]>块

我试图使用PHP解析XML文件,但收到一条错误消息:

分析器错误:字符0x0超出了中允许的范围

我认为这是因为XML的内容,我认为有一个特殊的符号“☆", 我能做些什么来修复它

我还得到:

分析器错误:标记项行中的数据过早结束

是什么导致了这个错误

我正在使用

更新:
我试图找到错误行并将其内容粘贴为单个xml文件,它可以工作!!因此我仍然无法找出导致xml文件解析失败的原因。PS这是一个超过100米的大型xml文件,它会导致解析错误吗?

您是否可以控制xml?如果可以,请确保数据包含在
]>
块中

您还需要清除无效字符:

/**
 * Removes invalid XML
 *
 * @access public
 * @param string $value
 * @return string
 */
function stripInvalidXml($value)
{
    $ret = "";
    $current;
    if (empty($value)) 
    {
        return $ret;
    }

    $length = strlen($value);
    for ($i=0; $i < $length; $i++)
    {
        $current = ord($value{$i});
        if (($current == 0x9) ||
            ($current == 0xA) ||
            ($current == 0xD) ||
            (($current >= 0x20) && ($current <= 0xD7FF)) ||
            (($current >= 0xE000) && ($current <= 0xFFFD)) ||
            (($current >= 0x10000) && ($current <= 0x10FFFF)))
        {
            $ret .= chr($current);
        }
        else
        {
            $ret .= " ";
        }
    }
    return $ret;
}
/**
*删除无效的XML
*
*@access-public
*@param字符串$value
*@返回字符串
*/
函数stripInvalidXml($value)
{
$ret=“”;
$current;
if(空($value))
{
返回$ret;
}
$length=strlen($value);
对于($i=0;$i<$length;$i++)
{
$current=ord($value{$i});
如果($current==0x9)||
($current==0xA)||
($current==0xD)||

($current>=0x20)&&&($current=0xE000)&&($current=0x10000)&&($current如果您对数据有控制权,请确保数据编码正确(即使用您在xml标记中承诺的编码,例如,如果您有:

<?xml version="1.0" encoding="UTF-8"?>

然后您需要确保您的数据是UTF-8格式的

如果你无法控制数据,就对那些控制数据的人大喊大叫


您可以使用类似的工具来检查数据的哪些部分无效。

确保您的XML源有效。有关将此类输入加载到SimpleXMLElement的非破坏性方法,请参阅我的回答。

我决定测试所有值(0-1114111)确保一切正常运行。在测试所有utf-8值时,由于错误,使用会导致返回NULL。这就是我提出的解决方案

$utf_8_range = range(0, 1114111);
$output = ords_to_utfstring($utf_8_range);
$sanitized = sanitize_for_xml($output);


/**
 * Removes invalid XML
 *
 * @access public
 * @param string $value
 * @return string
 */
function sanitize_for_xml($input) {
  // Convert input to UTF-8.
  $old_setting = ini_set('mbstring.substitute_character', '"none"');
  $input = mb_convert_encoding($input, 'UTF-8', 'auto');
  ini_set('mbstring.substitute_character', $old_setting);

  // Use fast preg_replace. If failure, use slower chr => int => chr conversion.
  $output = preg_replace('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', '', $input);
  if (is_null($output)) {
    // Convert to ints.
    // Convert ints back into a string.
    $output = ords_to_utfstring(utfstring_to_ords($input), TRUE);
  }
  return $output;
}

/**
 * Given a UTF-8 string, output an array of ordinal values.
 *
 * @param string $input
 *   UTF-8 string.
 * @param string $encoding
 *   Defaults to UTF-8.
 *
 * @return array
 *   Array of ordinal values representing the input string.
 */
function utfstring_to_ords($input, $encoding = 'UTF-8'){
  // Turn a string of unicode characters into UCS-4BE, which is a Unicode
  // encoding that stores each character as a 4 byte integer. This accounts for
  // the "UCS-4"; the "BE" prefix indicates that the integers are stored in
  // big-endian order. The reason for this encoding is that each character is a
  // fixed size, making iterating over the string simpler.
  $input = mb_convert_encoding($input, "UCS-4BE", $encoding);

  // Visit each unicode character.
  $ords = array();
  for ($i = 0; $i < mb_strlen($input, "UCS-4BE"); $i++) {
    // Now we have 4 bytes. Find their total numeric value.
    $s2 = mb_substr($input, $i, 1, "UCS-4BE");
    $val = unpack("N", $s2);
    $ords[] = $val[1];
  }
  return $ords;
}

/**
 * Given an array of ints representing Unicode chars, outputs a UTF-8 string.
 *
 * @param array $ords
 *   Array of integers representing Unicode characters.
 * @param bool $scrub_XML
 *   Set to TRUE to remove non valid XML characters.
 *
 * @return string
 *   UTF-8 String.
 */
function ords_to_utfstring($ords, $scrub_XML = FALSE) {
  $output = '';
  foreach ($ords as $ord) {
    // 0: Negative numbers.
    // 55296 - 57343: Surrogate Range.
    // 65279: BOM (byte order mark).
    // 1114111: Out of range.
    if (   $ord < 0
        || ($ord >= 0xD800 && $ord <= 0xDFFF)
        || $ord == 0xFEFF
        || $ord > 0x10ffff) {
      // Skip non valid UTF-8 values.
      continue;
    }
    // 9: Anything Below 9.
    // 11: Vertical Tab.
    // 12: Form Feed.
    // 14-31: Unprintable control codes.
    // 65534, 65535: Unicode noncharacters.
    elseif ($scrub_XML && (
               $ord < 0x9
            || $ord == 0xB
            || $ord == 0xC
            || ($ord > 0xD && $ord < 0x20)
            || $ord == 0xFFFE
            || $ord == 0xFFFF
            )) {
      // Skip non valid XML values.
      continue;
    }
    // 127: 1 Byte char.
    elseif ( $ord <= 0x007f) {
      $output .= chr($ord);
      continue;
    }
    // 2047: 2 Byte char.
    elseif ($ord <= 0x07ff) {
      $output .= chr(0xc0 | ($ord >> 6));
      $output .= chr(0x80 | ($ord & 0x003f));
      continue;
    }
    // 65535: 3 Byte char.
    elseif ($ord <= 0xffff) {
      $output .= chr(0xe0 | ($ord >> 12));
      $output .= chr(0x80 | (($ord >> 6) & 0x003f));
      $output .= chr(0x80 | ($ord & 0x003f));
      continue;
    }
    // 1114111: 4 Byte char.
    elseif ($ord <= 0x10ffff) {
      $output .= chr(0xf0 | ($ord >> 18));
      $output .= chr(0x80 | (($ord >> 12) & 0x3f));
      $output .= chr(0x80 | (($ord >> 6) & 0x3f));
      $output .= chr(0x80 | ($ord & 0x3f));
      continue;
    }
  }
  return $output;
}
我的问题是“&”字符(十六进制0x24),我改为:

function stripInvalidXml($value)
{
    $ret = "";
    $current;
    if (empty($value)) 
    {
        return $ret;
    }

    $length = strlen($value);
    for ($i=0; $i < $length; $i++)
    {
        $current = ord($value{$i});
        if (($current == 0x9) ||
            ($current == 0xA) ||
            ($current == 0xD) ||

            (($current >= 0x28) && ($current <= 0xD7FF)) ||
            (($current >= 0xE000) && ($current <= 0xFFFD)) ||
            (($current >= 0x10000) && ($current <= 0x10FFFF)))
        {
            $ret .= chr($current);
        }
        else
        {
            $ret .= " ";
        }
    }
    return $ret;
}
函数stripInvalidXml($value)
{
$ret=“”;
$current;
if(空($value))
{
返回$ret;
}
$length=strlen($value);
对于($i=0;$i<$length;$i++)
{
$current=ord($value{$i});
如果($current==0x9)||
($current==0xA)||
($current==0xD)||

($current>=0x28)&&&($current=0xE000)&&&($current=0x10000)&&($current不是php解决方案,但它可以:

下载记事本++

在记事本中打开.xml文件++

从主菜单:搜索->搜索模式将其设置为:扩展

那么

替换->查找内容\x00;替换为{留空}

然后,全部替换


Rob

某些Unicode字符:

  • C0控制代码(U+0000-U+001F)除制表符、CR和LF外
  • UTF-16代理(U+D800-U+DFFF)。这些在UTF-8中也是无效的,并且在遇到问题时指示更严重的问题
  • U+FFFE和U+FFFF
但在实践中,您经常需要处理从包含此类字符的其他来源不小心生成的XML。如果您想处理UTF-8编码字符串中无效XML的这种特殊情况,我建议:

$str = preg_replace(
    '/[\x00-\x08\x0B\x0C\x0E-\x1F]|\xED[\xA0-\xBF].|\xEF\xBF[\xBE\xBF]/',
    "\xEF\xBF\xBD",
    $str
);
这不使用
u
Unicode正则表达式修饰符,而是直接作用于UTF-8编码字节以获得额外性能。模式的部分包括:

  • 无效的控制字符:
    [\x00-\x08\x0B\x0C\x0E-\x1F]
  • UTF-16代理项:
    \xED[\xA0-\xBF]。
  • 非字符U+FFFE和U+FFFF:
    \xEF\xBF[\xBE\xBF]

无效字符将替换为替换字符U+FFFD(�) 而不是简单地剥离它们。这使诊断无效字符变得更容易,甚至可以。我不能控制XML,但我可以问……但这是解决方案??让我检查一下,不确定这在这种情况下是否有帮助。CDATA无法解决编码问题,只能回避诸如“&”而不是“&”之类的问题;“。是的,我同意。Dominic有解决方案。user315396:抱歉,您无法用CData节修复“超出允许范围”。此函数已损坏。
ord()
只对单个字节进行操作。我试图找到错误行并将其内容粘贴为单个xml文件,它可以工作!!因此我仍然无法找出导致xml文件解析失败的原因。在这种情况下,这正好强化了Dominic的说法。好吧……我认为某些数据不是UTF-8。实际上,如果我在FF打开xml,就会出现错误消息错误字符。即…嗯…这是一个大文件。我只是等待了很长时间,但没有响应。@DominicRodger谢谢!xmllint让我找到无效字符并删除它们。XML是有效的,如果编码是UTF-8,但有一个大5字符,我找到了字符“".这非常有帮助!虽然我还没有找到触发“long”版本的输入,但您有什么需要的示例吗?@mcfedr preg_replace可以在以后的php版本中修复。我相信这是PHP5.4
$str = preg_replace(
    '/[\x00-\x08\x0B\x0C\x0E-\x1F]|\xED[\xA0-\xBF].|\xEF\xBF[\xBE\xBF]/',
    "\xEF\xBF\xBD",
    $str
);