ブログの更新情報をPINGZONE経由でPingサーバーに送信
先日構築中のサイトにRSS2.0とAtomのフィードを生成する機能を追加しました
何故この機能を追加したか?
通常PING送信はPINGサーバーのアドレスに対して個別に送信します
有名なPINGサーバーというとGoogleブログ検索でしょうか
他にもいろいろありますが、突然無効になったりすることもあり、
個別に送信しているとメンテナンスが非常に面倒です
この問題を解決するために利用しているのが「PINGZONE」です
利用手順(会員登録していない場合)
これで複数のPIGNサーバーに一斉にPING送信できます
注意点は以下の記述を
内に記述すること<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="http://otaku.kansai-fan.com/rss2.xml" /> <link rel="alternate" type="application/atom+xml" title="Atom" href="http://otaku.kansai-fan.com/atom.xml" />
この記述がないと最新更新ブログ一覧にブログ情報が追加されません
PING送信も恐らく失敗している
ちなみにAtomに対応していないのか以下の記述だと同様の現象が発生します
<link rel="alternate" type="application/atom+xml" title="Atom" href="http://otaku.kansai-fan.com/atom.xml" />
hrefを相対パスで指定した場合も同様の現象が発生します
私は最初相対パスで記述しており気付くまで数時間費やしてしまいました・・・
PINGZONEは会員登録するとPINGZONEにPING送信するだけで上記の一連の処理を行ってくれます
自サイトにはまだPINGZONEにPING送信する機能は実装していません
次実装するのはフィードの作成後にPINGZONEにPING送信する機能になりそうです
意外と簡単にphpでRSS2.0とAtomのフィードを生成できた
自前で構築中のサイトの記事作成時にRSS2.0とAtomのフィードを生成する機能を追加してみました。
使ったのはPHP Universal Feed Generatorというライブラリ
記事データ
実際はデータベース等から取得して連想配列に格納します
<?php $item1 = array(); $item2 = array(); $item1["title"] = "タイトル2"; $item1["link"] = "http://otaku.kansai-fan.com/content/20170502"; $item1["date"] = strtotime(date('Y-m-d G:i:s', time())); $item1["author"] = "投稿者2"; $item1["description"] = "投稿内容2"; $item2["title"] = "タイトル1"; $item2["link"] = "http://otaku.kansai-fan.com/content/20170501"; $item2["date"] = strtotime(date('Y-m-d G:i:s', time())); $item2["author"] = "投稿者1"; $item2["description"] = "投稿内容1"; $list = array(); $list["20170502100000"] = $item1; $list["20170502090000"] = $item2; ?>
RSS2.0
<?php // ライブラリの読み込み use \FeedWriter\RSS2; // チャンネル情報の登録 $feed = new RSS2; $feed->setTitle("とあるオタクの備忘録"); $feed->setLink("http://otaku.kansai-fan.com/"); $feed->setDate(new DateTime()); $feed->setDescription("プレイ中のゲームのプレイ日記等"); $feed->setImage("http://otaku.kansai-fan.com/" , "とあるオタクの備忘録", "http://otaku.kansai-fan.com/image/logo.png" ); $feed->setChannelElement( "language" , "ja-JP" ); $feed->setChannelElement( "pubDate" , date(\DATE_RSS , time())); $feed->setChannelElement( "category" , "Blog" ); // 記事の分だけ、フィードのアイテムを追加する foreach ($list as $key => $value){ $data = $value; $item = $feed->createNewItem(); $item->setTitle($data["title"]); $item->setLink($data["link"]); $item->setDate($data["date"]); $item->setAuthor($data["author"]); $item->setDescription($data["description"]); $item->setId($data["link"], true) ; $feed->addItem($item); } // xml形式の文字列を出力 $xml = $feed->generateFeed(); // ファイルの保存場所を設定 $file = "/home/aaa/bbb/rss2.xml"; // ファイルの保存を実行 @file_put_contents($file, $xml); ?>
<?php // ライブラリの読み込み use \FeedWriter\ATOM; // チャンネル情報を登録 $feed = new ATOM; $feed->setTitle("とあるオタクの備忘録"); $feed->setLink("http://otaku.kansai-fan.com/"); $feed->setDate(new DateTime()); // 記事の分だけ、フィードのアイテムを追加する foreach ($list as $key => $value){ $data = $value; $item = $feed->createNewItem(); $item->setTitle($data["title"]); $item->setLink($data["link"]); $item->setDate($data["date"]); $item->setAuthor($data["author"]); $item->setDescription($data["description"]); $feed->addItem($item); } // xml形式の文字列を出力 $xml = $feed->generateFeed(); // ファイルの保存場所を設定 $file = "/home/aaa/bbb/atom.xml"; // ファイルの保存を実行 @file_put_contents($file, $xml) ; ?>
RSS2.0とAtomで設定する項目が少し異なるくらいで処理はほぼ変わりません。
RSS1.0は今回作成してませんが、ほぼ同じ流れで簡単に作成できそうです。
気を付けないといけないのは日付関連の項目
値が不正だとgenerateFeedメソッドでエラーが発生します
実際に出力したものがこちら
PHPのfile関数でcsvを読み込んだ時に改行コードが含まれていた
下記のようなcsvファイルを読み込んでweb上に表示させる画面を作りました
20170410,タイトル1 20170411,タイトル2 20170412,タイトル3 20170413,タイトル4 20170414,タイトル5
まずfile関数で1行ずつ配列に格納しました
<?php $array = file("/history.csv"); // $array[0]は"20170410,タイトル1" // $array[1]は"20170411,タイトル2" ?>
後はこの配列をループさせて画面に表示するだけ
<?php $array = file("/history.csv"); $content .= "<ul>"; for($i = 0;$i < count($array);$i++){ $str = split(",", $array[$i]); $dt = date('Y/m/d', strtotime($str[0])); $content .= "<li>".$dt." ".$str[1]."</li>"; } $content .= "</ul>"; echo $content; ?>
画面で表示した結果
2017/04/10 タイトル1 2017/04/11 タイトル2 2017/04/12 タイトル3 2017/04/13 タイトル4 2017/04/14 タイトル5
ここまではよかったのですが、この配列にデータを追加してその内容でcsvファイルを更新ようとした時問題が発生しました。
<?php $array = file("/history.csv"); array_push($array, "20170415,タイトル6"); $file = fopen("/history.csv", "w"); for($i = 0;$i < count($array);$i++){ @fwrite($file, $array[$i]."\r\n"); } fclose($file); ?>
出力したcsvファイル
2017/04/10 タイトル1 2017/04/11 タイトル2 2017/04/12 タイトル3 2017/04/13 タイトル4 2017/04/14 タイトル5 2017/04/15 タイトル6
何故か改行が増えてる・・・
改行コードは1個だけしか付加してないのに
原因はfile関数でcsvファイルを読み込む時に改行コードまで読み込んでいたから
読み込んだ時に下記のようになっていたということです
<?php $array = file("/history.csv"); // $array[0]は"20170410,タイトル1\r\r" // $array[1]は"20170411,タイトル2\r\r" ?>
file関数オプションにFILE_IGNORE_NEW_LINESを追加することで改行コードは付加されずに読み込まれます
<?php $array = file("/history.csv", FILE_IGNORE_NEW_LINES); // $array[0]は"20170410,タイトル1" // $array[1]は"20170411,タイトル2" ?>
修正後に出力したcsvファイル
2017/04/10 タイトル1 2017/04/11 タイトル2 2017/04/12 タイトル3 2017/04/13 タイトル4 2017/04/14 タイトル5 2017/04/15 タイトル6
正規表現で特定の文字列を含まない行、含む行を抽出
先日とある会社のシステムのリリースがありました。
かなり大規模なシステムなので予想通りリリース後
いろいろと問題が発生し、ログ解析する日々です。
ログのフォーマット
2017/03/22 12:00:03 INFO START testAction1.do 2017/03/22 12:00:06 INFO END testAction1.do 2017/03/22 12:00:08 INFO START xxxAction2.do 2017/03/22 12:00:10 FATAL java.lang.NullPointerException ・ ・ ・ javax.servlet.http.HttpServlet.service(HttpServlet.java:617) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) ・ ・ ・ 2017/03/22 12:03:08 INFO START xxxAction3.do 2017/03/22 12:00:10 WARN xxx.ValidateException ・ ・ ・ javax.servlet.http.HttpServlet.service(HttpServlet.java:617) javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
Javaで構築されたシステムで、予期しない例外が発生するとログに内容が出力されます。
ログから"Exception"を含む行を秀丸エディタでgrepして目的の行を検索するのですが、使用しているフレームワークが出力する例外(ValidateException)が大量に出力されて数千件ヒットしてしまいます。
そこで正規表現を使って"Exception"を含む行かつ
"ValidateException"を含まない行を抽出できるようにしました
^(?!.*ValidateException).*(?=Exception).*$
^(?!.*ValidateException).*$で"ValidateException"を含まない行がマッチします。
そこに(?=Exception)を合わせることによって
"ValidateException"を含まない行、
かつ"Exception"を含む行がマッチします。
これで検索結果がかなり絞られましたが、他にもチェック不要な例外(TimeOutException)が
あることが判明
この例外も除外したいので"ValidateException"と"TimeOutException"を含まない行に条件を変更しました
^(?!.*(ValidateException|TimeOutException)).*(?=Exception).*$
除外したい文字列を()で囲んで|で区切るだけです。
これでログ解析の効率がかなりアップしましたよ。