PHPで今日は何の日か調べる(Windowsアプリ版)

(1/1)
PHPを使うと、簡単にサイトの情報を取り出す(スクレイピング)ことができる。「PHPで今日は何の日か調べる」では、Wikipedia および 一般社団法人 日本記念日協会にアクセスし、今日の出来事を調べるプログラムをつくった。今回は、これをWindowsアプリに移植する。

(2021年1月31日)記念日も表示するようにした。

サンプル・プログラム

PHPでWindowsアプリ開発:今日は何の日

目次

解説:calendar

0317: /**
0318:  * 検索結果一覧
0319:  * @param int $windowウィンドウID
0320:  * @return stringなし
0321: */
0322: function putItems($window) {
0323:     global $Items;
0324: 
0325:     clear_error($window);
0326:     wb_delete_items(wb_get_control($windowIDC_RES_LISTVIEW));
0327:     $Items = array();
0328: 
0329:     $t = wb_get_value(wb_get_control($windowIDC_CALENDAR));
0330:     $month = date('m', $t) + 0;
0331:     $day   = date('d', $t) + 0;
0332: 
0333:     $i = getDayToday($month$day$Items);
0334:     $i = getAnniversary($month$day$Items$errmsg$i);
0335:     usort($Items, 'sortItems');
0336: 
0337:     //表示
0338:     if ($i > 0) {
0339:         wb_create_items(wb_get_control($windowIDC_RES_LISTVIEW), $Items);
0340:     } else {
0341:         put_error($windowERROR_NOTCONNECTED);
0342:     }
0343: }

月日の選択は、Winowsの calendarコントロール を利用する。
WinBinder関数 wb_get_value を呼び出すことで、現在選択されている年月日をUNIX TIMEで取り出すことができる。これを組み込み関数  date  に通せば、月と日を取得できるという仕組みである。

解説:https通信対応

0134: /**
0135:  * httpsサイトからコンテンツを受信
0136:  * @param string $url "https://" から始まるURL
0137:  * @param array  $post POST変数を格納した連想配列("変数名"=>"値") 
0138:  * @return string取得したコンテンツ/FALSE取得エラー
0139: */
0140: function file_get_contents_ssl($url$post=NULL) {
0141:     $ch = curl_init($url);
0142:     curl_setopt($chCURLOPT_HEADERFALSE);
0143:     curl_setopt($chCURLOPT_RETURNTRANSFERTRUE);
0144:     if ($post != NULL) {
0145:         curl_setopt($chCURLOPT_POSTTRUE);
0146:         curl_setopt($chCURLOPT_POSTFIELDShttp_build_query($post));
0147:     }
0148:     curl_setopt($chCURLOPT_SSL_VERIFYPEERFALSE); //サーバ証明書検証をスキップ
0149:     curl_setopt($chCURLOPT_SSL_VERIFYHOSTFALSE); //  〃
0150:     $result = curl_exec($ch);
0151:     curl_close($ch);
0152: 
0153:     return $result;
0154: }

Wikipediaのサイトが https 化したことにともない、コンテンツの取得をhttpsプロトコルで行わなければならない。 fopen  や  file_get_contents  では bamcompile がhttpsプロトコルに対応していないようなので、「PHPセキュリティ対策:SSL通信を行う」で紹介したCURL, Client URL Library 関数を利用することにする。
php.iniextension=php_curl を有効にする必要があるため、本プログラム線用の php.ini を "daytodaywin\" ディレクトリに配置し、コンパイル時に読み込むようにしてある。

第二引数 $post を指定したときは、POST渡しできるようにしている。これは、日本記念日協会にアクセスするときに使う。

解説:Wikipediaをスクレイピング

0190: /**
0191:  * 今日は何の日 取得
0192:  * @param int $month, $day月,日
0193:  * @param array $items情報格納配列
0194:  * @param bool $lfn 脚注残す(省略時=FALSE)
0195:  * @return int情報件数
0196: */
0197: function getDayToday($month$day, &$items$lfn=FALSE) {
0198:     $pat1 = "<span[\s\S]+id=\"できごと\">";
0199:     $pat2 = "<span[\s\S]+id=\"誕生日\">";
0200:     $pat3 = "<span[\s\S]+id=\"忌日\">";
0201:     $pat5 = "<li>[^\>]+([0-9]+年.+)<\/li>";
0202:     $pat6 = "([^0-9]*)([0-9]+)年(\s*[\((].[^\))]+[)\)].)?[ \-]+(.+)";   //年 - イベント
0203:     $pat7 = "([^0-9]*)([0-9]+)年[ \-]+(.+)?、([^(\(]+)*[^0-9]*([0-9]*)";
0204:                                                     //年 - 名前、職業(生没年)
0205:     $pat8 = "<span[\s\S]+id=\"フィクションのできごと\">";
0206: 
0207:     //コンテンツ読み込み
0208:     $url = getURL_Wikipedia($month$day);
0209:     $contents = file_get_contents_ssl($url);
0210:     if ($contents == FALSE)     return FALSE;
0211: 
0212:     //解釈
0213:     $str = strtok($contents, "\n");
0214:     $mode = '';
0215:     $cnt = 0;
0216:     while ($str != FALSE) {
0217:         if (mb_eregi($pat1$str) == 1) {
0218:             $mode = '出来事';
0219:         } else if (mb_eregi($pat8$str) == 1) {
0220:             $mode = '架空';
0221:         } else if (mb_eregi($pat2$str) == 1) {
0222:             $mode = '誕生';
0223:         } else if (mb_eregi($pat3$str) == 1) {
0224:             $mode = '死亡';
0225:         } else if ($mode != '' && mb_eregi($pat5$str$arr) > 0) {
0226:             $str = strip_tags(trim($str));
0227:             if ($mode == '出来事' && mb_eregi($pat6$str$arr) > 1) {
0228:                 $items[$cnt][0] = internal2sjis($mode);
0229:                 $items[$cnt][1] = ($arr[1] == '') ? (int)$arr[2] : 0 - $arr[2];
0230:                 $items[$cnt][2] = internal2sjis($lfn ? $arr[4] : eliminate_footnote($arr[4]));
0231:                 $cnt++;
0232:             } else if (mb_eregi($pat7$str$arr) > 1) {
0233:                 $items[$cnt][0] = internal2sjis($mode);
0234:                 $items[$cnt][1] = ($arr[1] == '') ? (int)$arr[2] : 0 - $arr[2];
0235:                 $items[$cnt][2] = internal2sjis($lfn ? $arr[3] : eliminate_footnote($arr[3]) . '' . $arr[4]);
0236:                 if ($arr[5] != '') {
0237:                     if ($mode == '誕生') {
0238:                         $items[$cnt][2] .= internal2sjis(';~' . $arr[5] . '');
0239:                     } else {
0240:                         $items[$cnt][2] .= internal2sjis('' . $arr[5] . '年~');
0241:                     }
0242:                 }
0243:                 $items[$cnt][2] .= internal2sjis('');
0244:                 $cnt++;
0245:             }
0246:         }
0247:         $str = strtok("\n");
0248:     }
0249: 
0250:     return $cnt;
0251: }

スクレイピングは正規表現を使って実装する。正規表現パターンは「PHPで今日は何の日か調べる」で説明したとおりである。
PHPでテキストの読みやすさを調べる(Windowsアプリ版)」で紹介したとおり、preg 系関数に動作不具合があるようなので、すべて mb_erege 系関数で処理している。

検索結果は「PHPで Windows用国立国会図書館検索プログラムをつくる」で使った ListView である。

解説:日本記念日協会をスクレイピング

0253: /**
0254:  * 日本記念日協会のページをスクレイピングして記念日を取り出す
0255:  * @param string $contentsページ内容
0256:  * @param array  $items 記念日を格納する配列
0257:  * @param int $cnt情報を追加する配列の最初の番号
0258:  * @return int情報の総数
0259: */
0260: function scrapingAnniversary($contents, &$items$cnt) {
0261:     $pat = '<a\s+class="winDetail"\s+href="([^"]+)"><font[^>]+>([^<]+)</font>';
0262:     $mode = '記念日';
0263: 
0264:     $tok = strtok($contents, "\n");
0265:     while ($tok != FALSE) {
0266:         if (mb_eregi($pat$tok$arr) > 0) {
0267:             $items[$cnt][0] = internal2sjis($mode);
0268:             $items[$cnt][1] = '';
0269:             $items[$cnt][2] = internal2sjis($arr[2]);
0270:             $cnt++;
0271:         }
0272:         $tok = strtok("\n");
0273:     }
0274: 
0275:     return $cnt;
0276: }

0278: /**
0279:  * 指定月日の記念日を取得する
0280:  * @param int $month, $day月日
0281:  * @param array $items   記念日を格納する配列
0282:  * @param string $errmsgエラーメッセージ格納用
0283:  * @param int $cnt情報を追加する配列の最初の番号
0284:  * @return int情報の総数
0285: */
0286: function getAnniversary($month$day, &$items, &$errmsg$cnt) {
0287:     //パラメータをPOST渡しする
0288:     $url = KINENBI_URL;
0289:     $post = array(
0290:         'MD' => $month,
0291:         'M'  => $month,
0292:         'D'  => $day
0293:     );
0294:     $errmsg = '';
0295: 
0296:     $res = file_get_contents_ssl($url$post);
0297:     if ($res == FALSE) {
0298:         $errmsg = '日本記念日協会のサイトにアクセスできません.';
0299:     } else {
0300:         $cnt = scrapingAnniversary($res$items$cnt);
0301:     }
0302: 
0303:     return $cnt;
0304: }

これは、「PHPで記念日を表示する」で紹介した [../php05/php05-21-01.shtm#scrapingAnniversary] および [../php05/php05-21-01.shtm#getAnniversary] 関数をPHP4に移植したものである。
日本記念日協会から、指定した月日の記念日を取得する。

コンパイル

コマンドラインから "bamcompile daytodaywin.bcp" を実行する。コンパイルが完了すると、"daytodaywin.exe" が生成される。"daytodaywin.exe" は、DLL不要で、単独で動作するEXEプログラムである。

参考サイト

(この項おわり)
header