Feedを受け取る側で以下のようなエラーが出てFeedできないという話(受け取る側は業者で,こちらはFeedする側).
Failed to fetch the RSS feed. Error: This XML document is invalid, likely due to invalid characters. XML error: Not well-formed (invalid token) at line 1, column 1
Feed XML は Validator をとおっていて,かつ手元の simplepie で XML をパースしてみても問題がない.
そもそも line 1, column 1 でコケているので,受け取る側の問題なのだが,対応してくれないので,こちらで対応することにした.
原因はサーバ側が deflate (gzip) されたデータを正しくハンドリングできないこと.つまり,
[S->C] GET /?feed=rss2 HTTP/1.1 Host: client.example.org User-Agent: SimplePie/1.3.1 (Feed Parser; http://simplepie.org; Allow like Gecko) Build/2015XXXXXXXXXX Accept-Encoding: x-gzip,gzip,deflate Accept: application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1 Connection: Close
のリクエストに対して
[C->S] HTTP/1.1 200 OK Date: Fri, 05 Feb 2016 XX:XX:XX GMT Server: Apache Set-Cookie: qtrans_front_language=ja; expires=Sat, 04-Feb-2017 XX:XX:XX GMT; Max-Age=31536000; path=/ Last-Modified: Mon, 01 Feb 2016 XX:XX:XX GMT ETag: (snip) Link: <http://client.example.org/?rest_route=/>; rel="https://api.w.org/" Content-Length: 8000 Connection: close Content-Type: application/rss+xml; charset=UTF-8 XMLデータ
のように Accept-Encoding: x-gzip,gzip,deflate を無視して RAW データ(といってもテキスト)を返す場合は OK だが,
[C->S] HTTP/1.1 200 OK Date: Fri, 05 Feb 2016 XX:XX:XX GMT Server: Apache Set-Cookie: qtrans_front_language=ja; expires=Sat, 04-Feb-2017 XX:XX:XX GMT; Max-Age=31536000; path=/ Last-Modified: Mon, 01 Feb 2016 XX:XX:XX GMT ETag: (snip) Link: <http://client.example.org/?rest_route=/>; rel="https://api.w.org/" Vary: Accept-Encoding Content-Encoding: gzip Content-Length: 2000 Connection: close Content-Type: application/rss+xml; charset=UTF-8 圧縮されたXMLデータ
のように律儀に(というか apache のデフォルト) Content-Encoding: gzip で返すとコケる.クライアントというか Feed する側にて,この特定のサーバに対して,以下のように圧縮しないように設定すれば解決./?feed=rss2 が Feed URL なので,以下のように RewriteCond/RewriteRule で対処(RewriteEngine Onとかはこの上付近にあることを想定).
RewriteCond %{QUERY_STRING} feed=rss2 RewriteCond %{REMOTE_HOST} XXX.XXX.XXX.XXX RewriteRule ^ - [E=no-gzip]
先方のサーバの設定が不明だが,Google で検索してもこの問題(の上記のような解決策)は出てこないようなので,かなりのコーナーケースな模様.
追記(2016/04/19)
WordPress の SimplePie の(サーバ側)該当箇所は wp-includes/SimplePie/File.php の以下の付近,だろうと思われる.
if (extension_loaded('zlib')) { $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n"; } // snip case 'gzip': case 'x-gzip': $decoder = new SimplePie_gzdecode($this->body); if (!$decoder->parse()) { $this->error = 'Unable to decode HTTP "gzip" stream'; $this->success = false; } else { $this->body = $decoder->data; } break; // snip
$decoder->parse()前後でコケているのだと思われるが (上流のエラーハンドリングまでは今回追わず),上のような問題が発生するような状況では if (extension_loaded('zlib')) の if 文まるごと削除してしまってもよいのかもしれない.