ipa 脆弱性情報

脆弱性情報をcronで毎日取得したい。
ソースはipa(情報処理推進機構)
https://www.ipa.go.jp/secuirty/rss/alert.rdf

中身がどうなっているかというと、itemの中は、title, link, dc:creator, dc:dateの4つだ。creatorは全部ipaだから、title,link,dateだけでいいか。

 <item rdf:about="https://www.ipa.go.jp/security/ciadr/vul/20190717-jre.html">
  <title>Oracle Java の脆弱性対策について(CVE-2019-7317等)</title>
  <link>https://www.ipa.go.jp/security/ciadr/vul/20190717-jre.html</link>
  <dc:creator>情報処理推進機構(IPA)</dc:creator>
  <dc:date>2019-07-17T12:00:00+09:00</dc:date>
 </item>

Soap

SOAP is a relatively simple protocol for computers on a network to exchange information. The main feature of SOAP is that all messages to been exchanged are summarized in XML.

<?xml version='1.0' encoding='UTF-8'?>
<SOAP-ENV:Envelope
	xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
	xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
	xmlns:xsd="http://www.w3.org/1999/XMLSchema">
	<SOAP-ENV:Body>
		<ns1:getRate
			xmlns:ns1="urn:demo1:exchange"
			>
			<country1 xsi:type="xsd:string">USA</country1>
			<country2 xsi:type="xsd:string">Japan</country2>
		</ns1:getRate>
	</SOAP-ENV:Body>
</SOAP-ENV:Envelop>

rss-phpでも、301リダイレクトのフィードからRSSを取得できるか?

composerでrss-phpを入れます。

[vagrant@localhost app]$ curl -sS https://getcomposer.org/installer | php
All settings correct for using Composer
Downloading...

Composer (version 1.6.5) successfully installed to: /home/vagrant/app/composer.phar
Use it: php composer.phar

[vagrant@localhost app]$ php composer.phar require dg/rss-php
Using version ^1.2 for dg/rss-php
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing dg/rss-php (v1.2): Loading from cache
Writing lock file
Generating autoload files
[vagrant@localhost app]$ ls
composer.json  composer.lock  composer.phar  index.php  vendor

rss-phpでfetchします。

require_once 'vendor/dg/rss-php/src/Feed.php';
$rss = Feed::loadRss('http://hpscript.com/rss/rss.xml');

foreach($rss->item as $item){
	echo $item->title ."<br>";
}

301リダイレクトを設定しているURLをfetchします。

require_once 'vendor/dg/rss-php/src/Feed.php';
$rss = Feed::loadRss('http://phone-search.online/test/index.php');

foreach($rss->item as $item){
	echo $item->title ."<br>";
}

OK つまり、301リダイレクトで、フィードのURLが変わっても、旧URLに301リダイレクトをかけている間は、新URLのフィードを取得できる。

rssフィードのurlが移転したときに、301リダイレクトで取得

xmlファイルをつくります。

<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>HPScript</title>
<link>http://hpscript.com/rss/test.xml</link>
<description>hpscriptのRSSです</description>
<language>ja-JP</language>
<item>
<guid isPermaLink="false"></guid>
<link>
SCSK
</link> <title>scsk</title> <description/> </item> <item> <guid isPermaLink="false"></guid> <link>
JBS
</link> <title>jbs</title> <description/> </item> </channel> </rss>

vagrantでphpファイルをつくって取得する。

$rss = simplexml_load_file('http://hpscript.com/rss/rss.xml');

foreach($rss->channel->item as $item){
	echo $item->title ."<br>";
}

モチ、ここまではOK

hpscript.com/rss/のディレクトリに.htaccessで301リダイレクトを書きます。

RewriteEngine on
RewriteRule ^index.php$ http://hpscript.com/rss/rss.xml [R=301,L]

http://hpscript.com/rss/index.php をたたくと、http://hpscript.com/rss/rss.xmlに301リダイレクトします。

では、vagrant側で、index.phpをfetchした場合。

$rss = simplexml_load_file('http://hpscript.com/rss/index.php');

foreach($rss->channel->item as $item){
	echo $item->title ."<br>";
}

取れてます!

では、下層ディレクトリから301リダイレクトをした場合。corpというディレクトリをつくり、301リダイレクトの設定をします。
下層ディレクトリでも全く同じで、301リダイレクトをすれば、取得できました。

RewriteEngine on
RewriteRule ^old.php$ http://hpscript.com/rss/rss.xml [R=301,L]

では、異なるドメインから301リダイレクトをした場合を考えたい。
http://phone-search.online/ というurl(電話のサービスづくりで取得したドメイン)にtestというディレクトリをつくり、同じように、301ディダイレクト設定を行う。

RewriteEngine on
RewriteRule ^old.php$ http://hpscript.com/rss/rss.xml [R=301,L]

phone-search.online/test/index.phpからfetchすると、

$rss = simplexml_load_file('http://phone-search.online/test/index.php');

foreach($rss->channel->item as $item){
	echo $item->title ."<br>";
}

ドメインが変わっても、301リダイレクトで取れている。
つまり、RSSのドメインが変わっても、旧URLに301リダイレクトが設定できれば、新しいURLのRSS取得はできる。

simplexml_load_file以外でもいけるか試したい。

simplexml_load_stringの使い方 2

<h3>xml</h3>
<?php

$axmlData = array();
$axmlData&#91;0&#93; = array 
		(
			"name"=> "楽天日本株4.3倍ブル",
			"rate" => "123.54",
			"asset" => "27625"
		);
$axmlData[1] = array
		(
			"name" => "小型株ファンド",
			"rate" => "107.11",
			"asset" => "24381"
		);
$sStringXML = '<?xml version="1.0" encoding="UTF-8"?>'."\n";
echo $axmlData[0][rate];
$sStringXML .= "<list>"."\n";
foreach($axmlData as $value){
	$sStringXML .= "<item>";
	$sStringXML.= "<return>".$value['rate']."</return>";
	$sStringXML .= "<toshin>".$value['name']."</toshin>";

	$sStringXML .= "<shisan>".$value['asset']."</shisan>";
	$sStringXML .= "</item>"."\n";
}
$sStringXML .= "</list>"."\n";
echo '[PHP ruler="true" toolbar="true"]'.htmlentities($sStringXML, ENT_QUOTES, 'UTF-8').'<\/pre>';
echo "<br>";
$xml = simplexml_load_string($sStringXML);

foreach($xml->item as $value){
	$name = $value->toshin;
	$return = $value->return;
	$asset = $value->shisan;

	echo 'name:'.$name.'<br/>';
	echo 'return:'.$return.'<br/>';
	echo 'asset:'.$asset.'<br>';
}
?>

name:楽天日本株4.3倍ブル
return:123.54
asset:27625
name:小型株ファンド
return:107.11
asset:24381

つまり、下記のxml:return, toshin, shisanを切り取ってくれるということですね。

<?xml version="1.0" encoding="UTF-8"?> <list> <item><return>123.54</return><toshin>楽天日本株4.3倍ブル</toshin><shisan>27625</shisan></item> <item><return>107.11</return><toshin>小型株ファンド</toshin><shisan>24381</shisan></item> </list>

Extracting xml Data

import xml.etree.ElementTree as ET

article_file = "exampleResearchArticle.xml"

def get_root(fname)
	tree = ET.parse(fname)
	return tree.getroot()

def get_authors(root):
	authors = []
	for author in root.findall('./fm/bibl/aug/au'):
		data = {
			"fnm": None,
			"snm": None,
			"email": None
		}
		data["fnm"] = author.find('./fnm').text
		data["snm"] = author.find('./snm').text
		data["email"] = author.find('./email').text

		authors.append(data)

	return authors

def test():
	solution = [{'fnm': 'Omer', 'snm': 'Mei-Dan', 'email': 'omer@extremegate.com'}, {'fnm': 'Mike', 'snm': 'Carmont', 'email': 'mcarmont@hotmail.com'}, {'fnm': 'Lior', 'snm': 'Laver', 'email': 'laver17@gmail.com'}, {'fnm': 'Meir', 'snm': 'Nyska', 'email': 'nyska@internet-zahav.net'}, {'fnm': 'Hagay', 'snm': 'Kammar', 'email': 'kammarh@gmail.com'}, {'fnm': 'Gideon', 'snm': 'Mann', 'email': 'gideon.mann.md@gmail.com'}, {'fnm': 'Barnaby', 'snm': 'Clarck', 'email': 'barns.nz@gmail.com'}, {'fnm': 'Eugene', 'snm': 'Kots', 'email': 'eukots@gmail.com'}]

	root = get_root(article_file)
	data = get_authors(root)

	assert data[0] == solution[0]
	assert data[1]["fnm"] == solution[1]["fnm"]

simplexml_load_file

simplexml_load_file:Interprets an XML file into an object

<?php

$rssList = array(
  "http://news.finance.yahoo.co.jp/rss/cp/fisf.xml",
  "http://news.finance.yahoo.co.jp/rss/cp/toyo.xml",
  "http://news.finance.yahoo.co.jp/rss/cp/mosf.xml",
  "http://news.finance.yahoo.co.jp/rss/cp/shikiho.xml"
);

for($n=0;$n<3;$n++){
    //URL設定
    $rssdata = simplexml_load_file("$rssList&#91;$n&#93;");

    // 件数設定
    $num_of_data = 3;

    //初期化
    $outdata = "";
    for ($i=0; $i<$num_of_data; $i++){

        $myEntry = $rssdata->channel->item[$i];
        $rssDate = $myEntry->pubDate;
        date_default_timezone_set('Asia/Tokyo');
        $myDateGNU = strtotime($rssDate);
        $myDate = date('Y/m/d',$myDateGNU);
        $myTitle = $myEntry->title; //タイトル取得
        $myLink = $myEntry->link; //リンクURL取得

        //出力内容(CSSOK)
        $outdata .=  '<p class=""><div style="float:left;width:80px;margin:0px 0px 0px 5px;font-size:12px">'.$myDate.'</div><a href="' . $myLink . '">' . $myTitle . '</a></p>';
    }
    echo $outdata; //全部出力する
}
?>

rssの種類
タグ RSS1.0 RSS2.0 Atom
要素 item channel entry
タイトル title title title
リンク link  link link
説明 description description description
日付 dc:date  pubDate issued

rssで取得したデータをmysqlに保存

a

$dbh = new PDO で接続、stmt->executeでsql文を実行
$stmt = $dbh->prepare(“insert into rss (title,link,site_title,site_link,date) values(?,?,?,?,?)”);
$stmt->execute(array($title,$link,$site_title,$site_link,$date));

reference
FETCH_ASSOC:Fetch a result row as an associative array

create table rss(
	id int not null auto_increment primary key,
	title varchar(255),
	link varchar(255),
	site_title varchar(64),
	site_link varchar(64),
	date datetime
);
<?php

try {
  $dbh = new PDO('mysql:host=localhost;dbname=test','dbuser','xxxx');
} catch(PDOException $e){
  var_dump($e->getMessage());
  exit;
}
$num = 5;//RSS取得件数

$rssUrl=array(
  'http://x6xo.hatenablog.com/rss',//サイトURL
);

//magpierss
require_once('./magpierss-master/rss_fetch.inc');
define('MAGPIE_OUTPUT_ENCODING', 'UTF-8');//encode
define('MAGPIE_CACHE_AGE','30');//cache

foreach($rssUrl as $no => $rss_url){
  if($rss_url != ''){
    //urlからRSSを取得
    $rss = @fetch_rss($rss_url);
      if($rss != NULL){
        for ($i=0; $i<count($rss->items); $i++){
          $rss->items[$i]["site_title"] = $rss->channel["title"];
          $rss->items[$i]["site_link"] = $rss->channel["link"];
        }
        // itemsを格納
        $rssItemsArray[] = $rss->items;
      }
  }
}

$concatArray = array();
if (is_array($rssItemsArray)) {
    for($i=0;$i<count($rssItemsArray);$i++){
    $concatArray = array_merge($concatArray,$rssItemsArray&#91;$i&#93;);//配列を統合する
  }

    foreach ($concatArray as $no => $values) {

        //RSSの種類によって日付を取得
        if($values['published']){$date = $values['published'];}
        elseif($values['created']){$date = $values['created'];}
        elseif($values['pubdate']){$date = $values['pubdate'];}
        elseif($values['dc']['date']){$date = $values['dc']['date'];}
        $date=date("Y-m-d H:i:s",strtotime($date));

        //Filter
        $nowtime = date("Y-m-d H:i:s",strtotime( "now" ));//現在時刻の取得
        if($date > $nowtime){//未来記事の排除
        }elseif(preg_match("/AD/", $values["title"])){//広告記事の排除
        }elseif(preg_match("/PR/", $values["title"])){
        }else{

            //値の定義
            $title=$values["title"];
            $link=$values["link"];
            $site_title=$values["site_title"];
            $site_link=$values["site_link"];

            //記事ごとに必要な項目を抽出
            $rssArray[]=array($date, $title, $link, $site_title, $site_link);
        }//
    }//

    //ソート
    function cmp($a, $b) {
        if ($a[0] == $b[0]) return 0;
        return ($a[0] > $b[0]) ? -1 : 1;
    }
    if($rssArray) { usort($rssArray, 'cmp'); }
    if(count($rssArray) > $num){$count=$num;}
    else{$count=count($rssArray);}

    for ($i=0; $i<$count; $i++) {
        $date=date("Y-m-d H:i:s",strtotime($rssArray&#91;$i&#93;&#91;0&#93;));
        $title=$rssArray&#91;$i&#93;&#91;1&#93;;
        $link=$rssArray&#91;$i&#93;&#91;2&#93;;
        $site_title=$rssArray&#91;$i&#93;&#91;3&#93;;
        $site_link=$rssArray&#91;$i&#93;&#91;4&#93;;
        $datelink = "<div>$date";
      $titlelink = "<a href='$link'>$title</a>";
      $site_titlelink = "<a href='$site_link'>[$site_title]</a></div>";
      echo "$datelink$titlelink$site_titlelink</div>";//(確認用)

      $stmt = $dbh->prepare("insert into rss (title,link,site_title,site_link,date) values(?,?,?,?,?)");
      $stmt->execute(array($title,$link,$site_title,$site_link,$date));
    }
}
?>

$stmt->fetchAll(PDO::FETCH_ASSOC) as $dataで、mysqlのデータを表示

<?php
// 接続
try {
  $dbh = new PDO('mysql:host=localhost;dbname=test','dbuser','xxxx');
} catch(PDOException $e){
  var_dump($e->getMessage());
  exit;
}
?>
<html>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>rss</title>
<body>
<?php

  date_default_timezone_set('Asia/Tokyo');

  $sql = "select * from rss order by date desc limit 10";
  echo '<table>';
  $stmt = $dbh->query($sql);
  foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $data){
    $date = date("m/d H:i",strtotime($data['date']));
    $title = ($data['title']);
    $link = ($data['link']);
    $site_link = ($data['site_link']);
    $site_title = ($data['site_title']);
    echo "<tr><td>$date</td><td><a href='$link'>$title</a></td><td><a href='$site_link'>[$site_title]</a></td></tr>";
  }

echo "</table>";

// 切断
$dbh = null;
?>