RSSフィードの取得エラーが出たときの問題の切り分けかた

# :book: はじめに
この記事は、[オールアバウト Advent Calendar 2016](http://qiita.com/advent-calendar/2016/allabout)の8日目の記事です。
先日は@takkyさんの[Welcome to Laravel Voyager](http://qiita.com/takky/items/1bc7349da185cc6b04d2)でした。
新卒1年目エンジニアの @amymd が、RSSフィード関係の実装を通して得た知見を共有できればと思います。


# :warning: 導入〜RSSフィード取得に失敗してる！さあどうしよう？

ある日のこと、自分はいつも通り会社に出社し、メールを確認しました。
すると、定期的にRSSを取得している処理がどうやら失敗しているようです。
RSS取得に失敗しているからといえ、この時点では、まだどこに問題があるかわかりません。
RSS取得の処理になにか問題あるかもしれませんし、RSS自体に問題があるのかもしれません。
その問題の切り分けをしていきましょう :muscle: 

# :memo: エラーログを確認する

基本中の基本ですが、まずはエラーログの内容を確認します。
[Logentries](https://logentries.com/)でログの管理を行っているため、サーバにSSHせずともブラウザから簡単にログを確認できます。大変便利です。

This XML document is invalid.等のXMLエラーの場合、RSSに問題があるかもしれません。
プログラムの処理に関するエラーが出ていると、RSSの取得処理に問題があるかもしれません。

まずはログの内容から、どちらの問題なのか目処を付けてみます。

# :eyes: RSSのどこが問題なのか調査する

RSSの問題だと思ったら、まずは該当のRSSをブラウザからアクセスしてみて、何かエラーが出てないか確認してみます。
また、特にブラウザ上では問題なくても、Validatorでチェックするとエラーが出ていることがあります。

[W3C Validator](https://validator.w3.org/feed/)

上記のURLでXMLに問題があるかチェックすることができます。
RSSのXMLやURL等を貼り付けて調べてみると、具体的にどの行でどのようなエラーが発生しているのかが表示されます。

以下は、自分が遭遇した問題の例をあげます。

## 例：CDATAセクションの中でCDATAセクションを呼び出していた

CDATAセクションとは、セクション内にマークアップが含まれず文字データのみを取り扱うことを示すものです。
https://msdn.microsoft.com/ja-jp/library/ms256076(v=vs.120).aspx

```xml
<![CDATA[An in-depth look at creating applications with XML, using <, >,]]>
```

このCDATAセクション内に、さらにCDATAセクションが埋め込まれていて、終端の`]]>`を誤認識してしまい、その結果下記のようなエラーが出ていました。

```
error on line 105 at column 3342: Opening and ending tag mismatch: encoded line 0 and script
```


## 例：「見えない文字」が原因で「This XML document is invalid.」

```
This XML document is invalid, likely due to invalid characters.
```

RSSを取得しようとすると上記のエラーが発生しておりました。

これは、XMLでは有効ではない文字列が含まれている、というエラーです。
原因を特定するために、先ほど示した[W3C Validator](https://validator.w3.org/feed/)を使用してみました。

しかし、そのエラーが発生している行を確認しても、あやしい文字はどこにも含まれていませんでした。

こういう時は、Sublime Textなどのエディタに、その箇所をコピペしてみます（自分は[mi](http://www.mimikaki.net/)というエディタに貼り付けました）。
すると、以下のように「見えない文字」が表示されました。

![93078497-f29d-f525-0009-05f0f12e411c.png](https://qiita-image-store.s3.amazonaws.com/0/42852/525bc3f3-ac71-4e5a-09da-c8e094acf34b.png)
※赤い背景に1Cとなっている箇所が、通常では見えない文字

このエディタ上で上記の文字を削除し、再度RSSを読み込んでみると……正常に取得できました！
原因はどうやらこの「見えない文字」のようです。

## :thinking: なぜこのような見えない文字が含まれてしまうのか

これは一概に「これが原因だ！」とは言い切れないのですが、
個人的な経験からすると、このような「見えない文字」は、OCRにかけたPDFからコピペしてくるときに紛れていたり、Macで作成したPDFをWindowsからコピペするときに紛れていたり、ということが多いような気がします。
それが原因なのかは定かではありませんが……。

他には、制御文字(BackSpaceなど)が原因ということもあるみたいです。

[WordPressのRSSフィードエラーは制御文字が原因？](http://www.infact1.co.jp/staff_blog/webmarketing/tool-app-soft/22664/)

ぱっと見てXMLに問題がなさそうであれば、このような症状を疑うと良いと思います。

# :inbox_tray: RSSを取得する処理に問題がある場合

RSSに特に問題が無いようであれば、RSSを取得する処理に問題があるかもしれません。
その処理を見直してみましょう。

以下は、自分が遭遇した問題の例をあげます。

## 例：RSS取得の処理に時間が掛かってタイムアウト

自分はLaravelというPHPのWebフレームワークを使用しており、 RSSをパースするLaravelのライブラリとして[Feeds](https://github.com/willvincent/feeds) を利用していました。

すると、とあるRSSを取得する際に、表示まで時間が掛かってしまい、下記のようなエラーが出てしまいました。

```
cURL error 28: Operation timed out after 10000 milliseconds with 0 bytes received
```

このライブラリでは、内部で[SimplePie](http://simplepie.org/)というRSSやAtomをパースするライブラリを使っており、cURLのデフォルトのタイムアウトの処理時間が10000msec…つまり10秒となっていました。

この設定を書き換えるには、Feedsライブラリを直接書き換える必要があるので、注意する必要があります。
（SimplePieオブジェクトなので `$this->simplepie->set_timeout(60)`のようにセットするとタイムアウトの時間を60秒にセットすることができます）

```php:FeedsFactory.php
public function make($feed_url = [], $limit = 0, $force_feed = false) {
    $this->simplepie = new SimplePie();
    $this->simplepie->set_timeout(60); // タイムアウトの秒数を指定
```


# :green_book: おわりに

今回はRSSが取得できなかったときの問題とその対応例を紹介しましたが、RSSフィードをパースして値を処理する際の問題など、まだまだあるかと思います。
中には、RSSの問題だとわかりつつも、RSSを処理する側でどうにかできたり、逆にRSSを修正しないとどうにもできなかったり…。
今回自分が得た知見が共有されて、少しでもみなさんの開発の一助となれば幸いです。