0

我正在尝试从 Wikipedia 获取数据,但是每次反序列化都失败。

示例查询应从 Honda Civic 页面获取第 20 节:

<?php
exec("curl -s 'http://en.wikipedia.org/w/api.php?action=parse&format=php&page=Honda_Civic&prop=text&section=20'", $output);

$value = "";
$first = true;
foreach ($output as $line) {
   if ($first) {
      $first = false;
   } else {
      $value .= "\n";
   }

   $value .= $line;
}

print("~~~\n");
print($value);
print("\n~~~\n");
print(unserialize($value));
print("~~~\n");

结果是:

~~~
a:1:{s:5:"parse";a:2:{s:5:"title";s:11:"Honda Civic";s:4:"text";a:1:{s:1:"*";s:1476:"<h4><span class="editsection">[<a href="/w/index.php?title=Honda_Civic&amp;action=edit&amp;section=1" title="Edit section: WTCC">edit</a>]</span> <span class="mw-headline" id="WTCC">WTCC</span></h4>
<p>Honda announced to enter the 2012 <a href="/wiki/World_Touring_Car_Championship" title="World Touring Car Championship">World Touring Car Championship</a> (WTCC) with a racer built on the 2012 Euro Civic 5 door hatchback. The car is powered by a 1.6-liter turbocharged engine, developed by Honda R&amp;D, and will race later in Japan, China and Macau before a two car team join the 2013 championship racing.<sup id="cite_ref-1" class="reference"><a href="#cite_note-1"><span>[</span>1<span>]</span></a></sup><sup id="cite_ref-2" class="reference"><a href="#cite_note-2"><span>[</span>2<span>]</span></a></sup><br />
<strong class="error">Cite error: There are <code>&lt;ref&gt;</code> tags on this page, but the references will not show without a <code>{{Reflist}}</code> template or a <code>&lt;references /&gt;</code> tag (see the <a href="/wiki/Help:Cite_errors/Cite_error_refs_without_references" title="Help:Cite errors/Cite error refs without references">help page</a>).</strong></p>


<!--
NewPP limit report
Preprocessor visited node count: 146/1000000
Preprocessor generated node count: 1599/1500000
Post‐expand include size: 3103/2048000 bytes
Template argument size: 1880/2048000 bytes
Highest expansion depth: 12/40
Expensive parser function count: 0/500
-->
";}}}
~~~
~~~

是的,存在“引用错误”,但数据仍应反序列化。知道这里发生了什么吗?

如果我从我的真实脚本中运行它(相对于这里给出的简化脚本),我会得到相同的输出,但也会得到以下可能有用的信息:

unserialize(): Error at offset 1583 of 1587 bytes
4

1 回答 1

2

您正在通过 curl 和 shell 传递数据,并且它会以破坏数据的方式被修改。

而是以不会破坏数据的方式获取数据,您应该没问题。

示例代码:

$url = 'http://en.wikipedia.org/w/api.php?action=parse&format=php&page=Honda_Civic&prop=text&section=20';

$buffer = file_get_contents($url);

$test = unserialize($buffer);

var_dump($test);

结果:

array(1) {
  'parse' =>
  array(2) {
    'title' =>
    string(11) "Honda Civic"
    'text' =>
    array(1) {
      '*' =>
      string(1476) "<h4><span class="editsection">[<a href="/w/index.php?title=Honda_Civic&amp;action=edit&amp;section=1" title="Edit section: WTCC">edit</a>]</span> <span class="mw-headline" id="WTCC">WTCC</span></h4>\n<p>Honda announced to enter the 2012 <a href="/wiki/World_Touring_Car_Championship" title="World Touring Car Championship">World Touring Car Championship</a> (WTCC) with a racer built on the 2012 Euro Civic 5 door hatchback. The car is powered by a 1.6-liter turbocharged engine, developed by Honda R&amp;D, and "...
    }
  }
}

那么为什么在一台计算机上出现错误,而在另一台计算机上却没有。这个错误是什么:

unserialize(): Error at offset 1583 of 1587 bytes

意思是?当 PHP 反序列化一个字符串时,它会根据它自己的格式对其进行解析。这种格式使它期望在不同的偏移量处有各种各样的东西。例如,字符串用双引号括起来,并以它们的长度为前缀(以字节为单位)。因此,解析器根据给定的长度移动到字符串的末尾,并检查是否在计算出的偏移量处找到了"双引号。在您的情况下,偏移量 1583 可能正是这种情况,但没有找到它。

当不同的字符编码具有不同的字符串字节长度时,这很可能是问题。例如,就在您提出问题的最后部分:

Preprocessor generated node count: 1599/1500000
Post‐expand include size: 3103/2048000 bytes
Template argument size: 1880/2048000 bytes

中的连字符Post‐expand实际上是Unicode Character 'HYPHEN' (U+2010)。它消耗序列化字符串中的三个字节。

但是,如果您通过外壳修改输出,则可以将其转换为外壳中使用的不同编码,因此破折号的字节长度仅为一个字节-因为它已转换为-(减号,ASCII连字符)消耗一个字节。

在另一个系统上,STDIO 可能不会破坏编码,因为它是 UTF-8 格式,因此不会中断。

另一种解决方法是告诉 curl 命令行工具写入临时文件,然后使用file_get_contents.

于 2013-04-30T01:19:15.993 回答