EasyBotterで日本語の人だけフォローする

Twitterのbot作成によく使われるEasyBotterをカスタマイズしてみます。

phpでTwitter botが作れるEasyBotter

pha氏が作成・公開しているEasyBotterをカスタマイズしてみます。

[link url=”http://pha22.net/twitterbot/”]

日本語の人だけフォローする

autoFollow()をオンにしておくと、フォローしてくれた人を自動でフォローバックしてくれて便利なのですが、異国の方々が一気に増えることがあります。

そこでプロフィールに日本語がある人だけをフォローするカスタマイズを行いました。

まずは autoFollow() を書き換える

こんな感じに差し替えます。

[php title=”EasyBotter.php” start-line=”227″ mark=”4-30″] return $results;
}

//自動フォロー返しする(プロフィールに日本語がある人だけ)
function autoFollow(){
$followers = $this->getFollowers();
$friends = $this->getFriends();
$followlist = array_diff($followers[“ids”], $friends[“ids”]);
if($followlist){
$j =0;
for ($i = 0; $i < count($followlist); $i++ ) { $j++; $user_list[] = $followlist[$i]; if ($j >= 100 or $i == count($followlist)) {
$profiles = $this->getProfiles($user_list);
foreach ($profiles as $user) {
$text = $user[‘name’] . $user[‘description’] . $user[‘status’][‘text’];
if (preg_match(‘/[ぁ-んァ-ヶ]/u’, $text)) {
$response = $this->followUser($user[‘id’]);
if(empty($response[“errors”])){
echo $response[“name”].”(@“.$response[“screen_name”].”)をフォローしました”;
}
}
}
$j = 0;
unset($user_list);
}
}
}
}

//============================================================
//上の5つの関数から呼び出す関数
//============================================================[/php]

未フォロワーリストから100件ずつプロフィールを読み込んで、「ひらがな」か「カタカナ」がある場合のみフォローしに行っています。

100件ずつなのはAPIの制限です。

プロフィールを取得する関数を作成する

こんな感じで getFollowers() の下辺りに追加します。

[php title=”EasyBotter.php” start-line=”570″ mark=”10-22″] function getFollowers()
{
$url = “https://api.twitter.com/1.1/followers/ids.json”;
$response = $this->_getData($url);
if($response[“errors”]){
echo $response[“errors”][0][“message”];
}
return $response;
}
function getProfiles($user_id = NULL)
{
$url = “https://api.twitter.com/1.1/users/lookup.json?”;
if ($user_id) {
$url .= ‘user_id=’ . implode(‘,’,$user_id) .”&”;
}
$url .= “include_entities=true”;
$response = $this->_getData($url);
if(isset($response[“errors”])){
echo $response[“errors”][0][“message”];
}
return $response;
}

function checkApi($resources = “statuses”){
$url = “https://api.twitter.com/1.1/application/rate_limit_status.json”;
if ($resources) {
$url .= ‘?resources=’ . $resources;
}[/php]

完成

これでプロフィールに日本語がある人だけをフォローするようになりました。

日本語といっても漢字だけの人は中国の方と判断が難しいので「ひらがな」か「カタカナ」が1文字でも含まれている人です。

記号としてひらがなを使っている異国の方はフォロー返しをしてしまいます。

言語設定が日本語の人だけフォローする

しばらくしてから気づきましたが、言語設定が「日本語」の人という条件にすれば良い気がしてきました。

こんな感じになります。

[php title=”EasyBotter.php” start-line=”230″ mark=”1,14″] //自動フォロー返しする(日本語設定の人だけ)
function autoFollow(){
$followers = $this->getFollowers();
$friends = $this->getFriends();
$followlist = array_diff($followers[“ids”], $friends[“ids”]);
if($followlist){
$j =0;
for ($i = 0; $i < count($followlist); $i++ ) { $j++; $user_list[] = $followlist[$i]; if ($j >= 100 or $i == count($followlist)) {
$profiles = $this->getProfiles($user_list);
foreach ($profiles as $user) {
if ($user[‘lang’] == ‘ja’) {
$response = $this->followUser($user[‘id’]);
if(empty($response[“errors”])){
echo $response[“name”].”(@“.$response[“screen_name”].”)をフォローしました”;
}
}
}
$j = 0;
unset($user_list);
}
}
}
}[/php]

この方がすっきりして良いですね。

誰でもやりたそうなカスタマイズなのに全然情報が無かったですね。

では、この辺で。(^-^)o

[WPプラグイン開発]設定画面を作成する

プラグイン作成に使える小技なんかを紹介していきたいと思います。

設定画面を作成する

自分で作ったWordPressプラグインに設定画面を追加してみます。

ソース

設定画面を表示するプラグインを作成してみます。

保存されている設定を読みだして、テキスト項目を設定して保存ができる設定画面です。

[php title=”my-test-plugin.php”]<?php
/*
Plugin Name: MyTestPlugin
Plugin URI: https://popozure.info/20180202/12305
Description: 設定画面を作成してみる
Version: 0.0.1
Network: True
Author: poporon
Author URI: http://popozure.info
License: GPLv2 or later
*/

defined(‘ABSPATH’) || die;

class MyTestPlugin {

public $options;

protected $defaults = array(
‘code1’ => ‘test’,
‘plugin-version’ => ‘0.0.0’
);

public function __construct() {
// オプション読み込み
$this->options = get_option(‘mytestplugin_options’, $this->defaults );

// 設定メニュー
add_action(‘admin_menu’, array($this, ‘add_menu’) );
}

// 管理画面のサブメニュー追加
public function add_menu() {
add_options_page(‘My Plugin Settings’, ‘Test Settings’, ‘manage_options’, ‘my-test-settings’, array($this, ‘page_settings’) );
}

// 設定画面
public function page_settings() {
if ( isset($_POST[‘properties’])) {
check_admin_referer(‘mytest_options’);
$this->options = $_POST[‘properties’];
update_option(‘mytestplugin_options’, $this->options);
}
?>
<div class=”wrap”>
<div id=”icon-options-general” class=”icon32″></div>
<h2>Test Settings</h2>
<div id=”settings” style=”clear:both;”>
<form action=”” method=”post”>
<?php wp_nonce_field(‘mytest_options’); ?>

<h3>Text Setting</h3>
<table class=”form-table”>
<tr valign=”top”>
<th scope=”row”>Code 1</th>
<td>
<input name=”properties[code1]” type=”text” id=”code1″ value=”<?php echo esc_attr($this->options[‘code1’]); ?>” class=”regular-text” style=”width: 8em;” />
</td>
</tr>
</table>
<?php submit_button(); ?>
</form>
</div>
</div>
<?php
}
}

$Class_MyTestPlugin = new MyTestPlugin;[/php]

動作イメージ

管理画面の設定に「Test Setting」という項目が増えています。

「Code 1」としてテキストが設定できる画面が表示されます。

文字列を変更して「変更を保存」を押すと、その文字列が記憶されます。

 解説

オプション項目の呼び出し・保存

何か設定項目を記録してもらいたいときに、設定画面を作りたくなると思います。覚えてもらう項目を「$options」と名付けてみます。(任意の名前で良いです。)

[php title=”my-test-plugin.php” start-line=”17″ wrap=”1″]public $options;[/php]

覚えて貰う項目の用意ができたので、今までにWordPressが覚えてくれている設定値を読み込みます。

[php title=”my-test-plugin.php” start-line=”26″ wrap=”1″]$this->options = get_option(‘mytestplugin_options’, $this->defaults );[/php]

WordPressが覚えてくれている「mytestplugin_options」というオプションを取得しています。

保存するときの名前と合わせます。

初めての呼び出しのときには、何も取得できないので、$defaultsの中身が入ります。

[php title=”my-test-plugin.php” start-line=”42″ wrap=”1″]update_option(‘mytestplugin_options’, $this->options);[/php]

変更したオプション($options)の内容を「mytestplugin_options」という名前で保存しています。

名前は自分の作るプラグインの名前に合わせて変更すると良いでしょう。

ちなみに「wp_options」というDBテーブルに記録されます。

管理画面のメニューに追加する

__construct内でアクションフックの設定を行います。

[php title=”my-test-plugin.php” start-line=”29″ wrap=”1″]add_action(‘admin_menu’, array($this, ‘add_menu’) );[/php]

管理画面のメニューが表示されるとき(admin_menu)にadd_menuという自分で作った関数(ルーチン)を呼びます。

add_menuという関数を定義して、その中で「設定」メニューにサブメニューを追加しています。

[php title=”my-test-plugin.php” start-line=”34″ wrap=”1″]add_options_page(‘My Plugin Settings’, ‘Test Settings’, ‘manage_options’, ‘my-test-settings’, array($this, ‘page_settings’) );[/php]

「My Plugin Settings」は任意の名称で良いです。

「Test Settings」は表示される文字列なので、分かり易い名称に直しましょう。

「manage_options」は設定メニューという意味なので、このまま変更しません。

「my-test-settings」は任意の名称で良いです。

「page_settings」は自分で作る関数の名前です。

[php title=”my-test-plugin.php” start-line=”38″ wrap=”1″]public function page_settings() {[/php]

先ほど用意したメニューを選んだときに表示されるのが「page_settings」という関数の中身です。

ここに設定したい内容とか、設定を保存する仕組みを書き入れます。

おまじない

他のページから呼ばれたときに誤動作しないように、ナンス(nonce)というのを設定しておきます。

[php title=”my-test-plugin.php” start-line=”50″ wrap=”1″]<?php wp_nonce_field(‘mytest_options’); ?>[/php]

更新をするときにチェックすることで、正しい順番でページが遷移(せんい)されてきたときだけオプションの更新を行います。

[php title=”my-test-plugin.php” start-line=”40″ wrap=”1″]check_admin_referer(‘mytest_options’);[/php]

「mytest_options」という名前は自分のプラグインの名称に合わせて直すと良いですが、フィールドを設定する側とチェック側とで合わせる必要があります。

おわり

今回は必要最小限の項目でプラグインの設定画面を作成してみました。

classを使ってプラグインの設定画面を作成する記事が少なくて、自分が困った記憶があったので、みなさんがプラグインを作成されるときの参考になれば幸いです。

では、この辺で。(^-^)o

[amzn-link asin=”4774187062″][amzn-link asin=”4798119873″][amzn-link asin=”4798143774″][amzn-link asin=”4295001244″][amzn-link asin=”4295000795″]

InstantWPでhtmlentitiesを使用すると文字化けする?

当サイトで公開している「Pz-LinkCard」で、InstantWPで使用した場合に「Pz カード管理画面」で文字化けするという現象が出ました。

色々と調べてみたところ、htmlentities関数のところで文字化けしていました。

文字セットが元々のデフォルトである「ISO-8859-1」として動作しているのだと思われます。

こんな表記のままだと、

[php title=”pz-linkcard-cacheman.php” start-line=”346″]$title = htmlentities($data->title);[/php]

文字化けします。

使用する文字セットを正しく指定してあげると、

[php title=”pz-linkcard-cacheman.php” start-line=”346″]$title = htmlentities($data->title, ENT_QUOTES, ‘UTF-8’);[/php]

正しく表示されました。

ちなみにhtmlentities関数とほとんど同じ動作をするはずのhtmlspecialchars関数を使用した場合には、文字セットなどを指定していなくても、

[php title=”pz-linkcard-cacheman.php” start-line=”346″]$title = htmlspecialchars($data->title);[/php]

正しく表示されるようです。

一応、php.iniで「default_charset = UTF-8」を設定してみたりもしたのですが変わりませんでした。

Apatchの設定も見たのですがよく分かりませんでした。

とりあえず表示させたいだけなので、htmlentities関数からhtmlspecialchars関数に差し替えました。

次期公開バージョンではInstantWPでも文字化けされず表示できる予定です。

では、この辺で。(^-^)o

phpでmetaタグとかOGP情報とかパースしたりしてみた

近日公開予定のリンクをブログカード形式で表示する「Pz-LinkCard」。

外部サイトのタイトルや概要文(抜粋文)をリンク先から取得するのですが…。

この記事は自分用のメモなので、かなりワケ分かんないと思います(^-^;

一個ずつpreg_matchしていた

リンク先のHTMLを取得したあと、OGPの情報を取得しています。

本当は「OpenGraph.php」とかを使うとラクなんだと思うのですが、「OGP無かったらTITLEタグからタイトル取得したり、最初のPタグから抜粋文取りたい」とか思ったのと、仕様変更とかあったら対応しないといけないので、なるべく自前でやりたいと思いました。

[link url=”http://www.kaasan.info/archives/1982″]

もちろん、脆弱性とか見つかったときに自前じゃなかったら勝手に対策してもらえるメリットとかもあるのですけど。

 

というか、正規表現とかまだ慣れていないので、マッチしたときに「楽しい!Σ(゚ロ゚)o゙」というのが、一番正直なところだったりします。

 

さて、今までは、「og:title」とか「og:description」とか、一個ずつ preg_match() で取得していました。

[php title=”pz-linkcard.php” start-line=”382″ decode=”true”]// OGPパース(タイトル)
if (preg_match(‘/.*<meta\s+(.*property\s*=\s*”og:title”\s*.*?)>/si’, $html, $m)) {
$param = $m[1];
if (preg_match(‘/.*content\s*=\s*”(.*?)”.*/si’, $param, $m)) {
$title = $m[1];
}
} else {
// OGPが無いときは、titleタグから取得
if (preg_match(‘/.*<title\s*.*>\s*(.*)\s*<\/title>.*/si’, $html, $m)) {
$title = $m[1];
}
}

// OGPの概要文
if (preg_match(‘/.*<meta\s+(.*property\s*=\s*”og:description”\s*.*?)>/si’, $html, $m)) {
$param = $m[1];
if (preg_match(‘/.*content\s*=\s*”(.*?)”.*/si’, $param, $m)) {
$excerpt = $m[1];
}
} elseif (preg_match(‘/.*<meta\s+(.*name\s*=\s*”*description”*\s*.*?)>/si’, $html, $m)) {
$param = $m[1];
if (preg_match(‘/.*content\s*=\s*”(.*?)”/i’, $param, $m)) {
$excerpt = $m[1];
}
} else {
// OGPが無いときは、最初の p要素を最初の段落として
if (preg_match(‘/<p>\s*(.*)<\/p>/si’, $html, $m)) {
$excerpt = $m[1];
}
}[/php]

一回「og:title」でマッチさせてから、「content」をマッチさせて…とやっているのは、<meta property=”og:title” content=”タイトルですよ!”> としているサイトと、<meta content=”タイトルですよ!” property=”og:title”> という感じで、contentが先に来ているサイトがあったから。

「出現順がどっちでもマッチさせる(どちらも含む)」表現だと、キーと値の順番が分かんなくなっちゃうので、og:title が含まれていたら、とりあえず metaタグの中身をドーンと持ってきて、content の値を持ってくる方法を取っていました。

 

get_meta_tags を使うと name と content の組み合わせを取得できるので description とかは取得できるのですが、OGP は property と content で指定されているので取得できないので、検索するしか無い気がします。

preg_match_all をつかってみた

まずは、取得してきた HTML からヘッダ( <head>~</head> の間)を抜き出します。

[php title=”pz-linkcard.php” start-line=”384″ decode=”true”]// HEADタグ
$head = null;
if (preg_match(‘/<head>(.*)<\/head>/si’, $html, $m)) {
$head = $m[1];
}[/php]

今度は、そこから preg_match_all() を使って、metaタグをドーンと取ってきて、name をキー、content を値にして、連想配列にしてみました。

[php title=”pz-linkcard.php” start-line=”401″ decode=”true”]// metaタグ パース
$match = null;
preg_match_all(‘/\s*meta\s*name=”?([^>”]*)”?\s*content=”?([^>”]*)”?\s*\/?>/si’, $head, $match);
if (isset($match) && is_array($match) && count($match) == 3) {
for ($i=0, $to_i=count($match[1]); $i < $to_i; $i++) {
$tags[$match[1][$i]] = esc_html($match[2][$i]);
}
}[/php]

空白が入ったり入らなかったりするところは、 \s* で「空白0個以上」。

ダブルクォートはあったり無かったりするところは、 “? で「ダブルクォート0個か1個」。

「ダブルクォート ” 」か「大なり > 」があるところまでを取りたいので、 [^>”]* で、 > と ” 以外 を 0個以上。

もうなんか、正規表現って書いてるとワケ分かんなくなってきますけど、マッチすると気持ちいいです。

慣れてる人なんかだとスラスラ読めちゃうんだと思うんですけど。

マッチしたらけっこうワケ分かんない感じで配列に入ってくるので、for でぶんまわして、うまいことキーと値を連想配列にしています。

ちなみに、「https://popozure.info/pz-hatenablogcard」から property と content の組み合わせの meta タグを取得した配列がこんな感じです。

Array
(
    [0] => Array
        (
            [0] => meta property="og:type" content="article" />
            [1] => meta property="og:title" content="WordPressで「はてなブログカード」を利用する Pz-HatenaBlogCard" />
            [2] => meta property="og:url" content="https://popozure.info/pz-hatenablogcard" />
            [3] => meta property="og:description" content="外部リンクを「はてなブログカード」に置き換えて表示させるWordPressプラグイン「Pz-HatenaBlo…" />
            [4] => meta property="article:published_time" content="2015-08-09T02:04:18+00:00" />
            [5] => meta property="article:modified_time" content="2015-09-26T18:42:27+00:00" />
            [6] => meta property="og:site_name" content="ぽぽづれ。" />
            [7] => meta property="og:image" content="http://mailbox.conohawing.com/popozure/blog/wp-content/uploads/2015/08/pz-hatenablogcard-thumbnail1.png" />
            [8] => meta property="og:image:width" content="279" />
            [9] => meta property="og:image:height" content="280" />
            [10] => meta property="og:locale" content="ja_JP" />
        )

    [1] => Array
        (
            [0] => og:type
            [1] => og:title
            [2] => og:url
            [3] => og:description
            [4] => article:published_time
            [5] => article:modified_time
            [6] => og:site_name
            [7] => og:image
            [8] => og:image:width
            [9] => og:image:height
            [10] => og:locale
        )

    [2] => Array
        (
            [0] => article
            [1] => WordPressで「はてなブログカード」を利用する Pz-HatenaBlogCard
            [2] => https://popozure.info/pz-hatenablogcard
            [3] => 外部リンクを「はてなブログカード」に置き換えて表示させるWordPressプラグイン「Pz-HatenaBlo…
            [4] => 2015-08-09T02:04:18+00:00
            [5] => 2015-09-26T18:42:27+00:00
            [6] => ぽぽづれ。
            [7] => http://mailbox.conohawing.com/popozure/blog/wp-content/uploads/2015/08/pz-hatenablogcard-thumbnail1.png
            [8] => 279
            [9] => 280
            [10] => ja_JP
        )

)

$match[1][1]が「og:title」、$match[2][1]が「WordPressで「はてなブログカード」を利用する Pz-HatenaBlogCard」となっている感じです。

count($match[1]) で、拾ってきた行数が分かるので、for でまわして、$match[1][$i] をキーに、$match[2][$i] を値にしている感じです。

 

このやり方は、PHPマニュアルサイトの get_meta_tags のノートを参考にしました。

[link url=”http://php.net/manual/ja/function.get-meta-tags.php”]

あとは取得するだけ

TITLE タグの内容とかも、一緒に連想配列に放り込んでおきました。

[php title=”pz-linkcard.php” start-line=”390″ decode=”true”]// TITLEタグ
if (preg_match(‘/<\s*title\s*.*>\s*(.*)\s*<\s*\/title\s*>/si’, $head, $m)) {
$tags[‘title’] = esc_html($m[1]);
}[/php]

あとは、取り出すだけです。

[php title=”pz-linkcard.php” start-line=”390″ decode=”true”]// タイトル
if (isset($tags[‘og:title’])) {
$title = $tags[‘og:title’];
} elseif (isset($tags[‘title’])) {
$title = $tags[‘title’];
}[/php]

大分シンプルな感じになりました。

使わないタグもいちいち配列に放り込むので処理時間はちょっと増えているかも知れませんが、2回目の表示からはDBから読み込んじゃうので問題無いと思います。

ファイル分けて、ちゃんと関数にして自分用のライブラリっぽくすると良さそうだなぁ。

引用符がダブルクォートじゃなくてシングルクォートのとき

[2015/10/06追記]

引用符がダブルクォートのときと、引用符が無いときは考えていたのですが、「シングルクォート」のときがありました(^-^;

つまり、ダブルクォートで囲まれていると、

<meta property=”og:title” content=”OGPパースを!正規表現で!”>

これでマッチさせて、

/\s*meta\s*property=”?([^>”]*)”?\s*content=”?([^>”]*)”?\s*\/?>/si

こんな結果になるのですが、

$match[0] meta property=”og:title” content=”OGPパースを!正規表現で!”>
$match[1] og:title
$match[2] OGPパースを!正規表現で!

シングルクォートで囲まれていると、

<meta property=’og:title’ content=’OGPパースを!正規表現で!’>

こんな感じで「’」が付いちゃいます。

 

$match[0] meta property=’og:title’ content=’OGPパースを!正規表現で!’>
$match[1] ‘og:title’
$match[2] ‘OGPパースを!正規表現で!’

これもマッチさせようとすると、こんな感じの正規表現になって、

/\s*meta\s*name=[\’\”]?([^>\’\”]*)[\’\”]?\s*content=[\’\”]?([^>\’\”]*)[\’\”]?\s*\/?>/si

今度はシングルクォートでもダブルクォートでも拾えるようになるけど、

<meta property=”og:title” content=”サマーフェスティバル’98”>

みたいに、「ダブルクォートで囲まれているけど、シングルクォート(というか、アポストロフィー)が入っている」というパターンの場合、途中で区切られてしまいます。

こんな感じで、シングルクォートもダブルクォートも「食う」感じにしておいて、

/\s*meta\s*property\s*=\s*([^>]*)\s+content\s*=\s*([^>]*)\s*\/?>/si

前後のクォートをトリムする!Σ(゚ロ゚)o゙

[php]$match[1][$i] = trim($match[1][$i], ‘\’\”‘ );
$match[2][$i] = trim($match[2][$i], ‘\’\”‘ );[/php]

trim関数は、先頭の1文字目と最後の1文字目の空白やタブを取り除く関数ですが、第二パラメータに取り除きたい文字を書いておくと、先頭の1文字目と最後の1文字目から外してくれるようです。

これで対応できるパターンが増えた気がします(^-^;

 

では(^-^)o

cURLを使ってサイトへアクセスしてみた

サイトのテキストを読み込んで、タイトル、本文、サムネイル画像とかを取得してみようと思います。

リンクをカード形式プラグイン

WordPressでリンク先を「はてなブログカード」で表示する「popo-HatenaBlogCard」を公開中。

[link url=”https://popozure.info/20150723/7753″]

「これを自前でやれないかなぁ?」という計画です。

 

今回は、リンク先からタイトルや本文(もしくは抜粋文、概要文)、サムネイル画像を取得してみようと思います。

file_get_contentsでHTML取得してみる

テキストファイルを読み込む file_get_contents()。

ファイル名の代わりにURLを指定することで、HTTPリクエストを送信することができるそうです。

[link url=”http://havelog.ayumusato.com/develop/php/e188-php_file_get_contents_tips.html”]

とりあえず、HTML取得して、かかった時間を測ってみます。

[php]$html = file_get_contents(‘https://popozure.info/20150723/7753’);[/php]

1.5秒~2.6秒くらいで取得できました。

 

HTMLソースが取得できた状態なので、ここからタイトルの取得とかを別途考えます。

cURLでHTML取得してみる

cURLというのを使うと、USER_AGENTとかREFERERを指定したり、cookie使ったりできるほか、PUTとか色々とアクセスができるようです。

[link url=”http://blog.mach3.jp/2010/12/21/use-curl-for-filegetcontents.html”]

「cURL初期化→cURLオプション指定→cURL実行→cURL閉じる」という手順が必要のようです。

とりあえず、HTML取得してみます。

[php] $ch = curl_init(‘https://popozure.info/20150723/7753’);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$html = curl_exec($ch);
curl_close($ch);[/php]

1.2秒~2.2秒くらいでした。

結果としては「file_get_contentsよりも速いのは確かだけど、誤差範囲」という感じでした。

 

手軽さでは file_get_contents、自由度では cURL という感じでしょうか。

HTMLソースが取得できただけなので、タイトルの取得などは別途考えます。

OpenGraph.phpを使ってみる

最近ではfacebookとかで使われている「OGP(;OpenGraph Protocol)」という仕様があって、タイトル、概要、画像、URL、サイト名なんかが記述されているブログが増えてきました。

OGPが設定されているサイトは、それを使うことでサイト側が意図した内容が表示される、ということになります。

 

HTMLのソースを取得して、そこからOGPの内容まで取得してくれる「OpenGraph.php」というのがあるようで、URLを指定するだけで、OGPの内容をオブジェクトとして返してくれます。

[link url=”http://www.kaasan.info/archives/1982″]

OpenGraph.phpは、「Apache License 2.0」ということなので、自分のプラグインに使って、一緒に頒布しても大丈夫そうです。

 

さっそく取得してみます。

[php] require_once(‘OpenGraph.php’);
$graph = OpenGraph::fetch($url);[/php]

取得にかかる時間は1.3秒~2.0秒。

内部ではcURLを使っているので、基本的には上のcURLを使っているのと同じ速度です。

 

あとは、

[php decode=”true”] echo ‘<br />title=’. $graph->title; // ページのタイトル
echo ‘<br />description=’. $graph->description; // ページの説明
echo ‘<br />image=’. $graph->image; // 画像URL
echo ‘<br />site_name=’. $graph->site_name; // サイト名[/php]

こんな感じで使うだけです。

↓結果

[crayon]title=リンクをカード形式にするプラグインを修正中
description=リンクカード形式で表示するプラグイン「HatenaBlogCard」を公開していますが、設定画面とかを付けたバ…
image=http://mailbox.conohawing.com/popozure/blog/wp-content/uploads/2015/07/popo-linkcard-shadow-300×100.png
image_src=
site_name=ぽぽづれ。[/crayon]

タイトルについては、「<meta property=”og:title” content=”○○○○”>」が無い場合には、「<title>○○○○</title>」からセットしてくれるようです。

 

あれ?これ使うだけでいいじゃんか!Σ(゚ロ゚)o゙

タイトル、抜粋文、サムネイル画像を抜き出してみる

どうせなので自分で抜出をしてみたいので、HTMLソースから、自分でOGP情報とかを抜き出してみようと思います。

とりあえず、metaタグで、property=”og:○○○○”とcontent=”○○○○”があるのを抜き出してみます。

[php decode=”true”] preg_match_all(‘/.*<meta\s+.*property\s*=\s*”og:(.*)”\s*content\s*=\s*”(.*)”.*>/i’, $html, $m)[/php]

$m [0] [1] [2]
[0] type article
[1] title リンクをカード形式にするプラグインを修正中
[2] url https://popozure.info/20150723/7753
[3] description リンクカード形式で表示するプラグイン「HatenaBlogCard」を公開していますが、設定画面とかを付けたバ…
[4] site_name ぽぽづれ。
[5] image http://mailbox.conohawing.com/popozure/blog/wp-content/uploads/2015/07/popo-linkcard-shadow-300×100.png
[6] locale ja_JP
[7]

 

しょっぱなからいい感じで取得できましたΣ(゚ロ゚)o゙

他のサイトさんでも試したところ、取得は出来たのですが、propertyとcontentの順番が逆のサイトさんがあり、上手く取れませんでした。

 

順不同でマッチさせると、結果もどっちに入っているのか分からなくなってしまうので、「property=”og:title”」が含まれるmetaタグを拾ってきてから、contentの中身を取得するようにしてみます。

[php decode=”true”] if (preg_match(‘/.*<meta\s+(.*property\s*=\s*”og:title”\s*.*?)>/i’, $html, $m)) {
$param = $m[1];
if (preg_match(‘/.*content\s*=\s*”(.*?)”.*/i’, $param, $m)) {
$title = $m[1];
}
}[/php]

一行目のpreg_matchで、metaタグの内容を取得。

$m [0] [1] [2]
property=”og:title” content=”リンクをカード形式にするプラグインを修正中” /

 

三行目のpreg_matchで、contentの中身を取得します。

 

$m [0] [1] [2]
property=”og:title” content=”リンクをカード形式にするプラグインを修正中” / リンクをカード形式にするプラグインを修正中

 

これなら、contentがpropertyよりも前でも後でも取得できそうです。

 

さらにはOGPが無かったときは<title>~</title>タグの中身を持ってくれば良さそうです。

[php start-line=”6″ decode=”true”] } else {
if (preg_match(‘/.*<title>\s*(.*)\s*<\/title>.*/i’, $html, $m)) {
$title = $m[1];
}
}[/php]

 

本文は、OGPがあれば「og:description」のcontentを、なければ「最初の<p>~</p>タグの中身」をもってくるようにしてみます。

[php decode=”true”] if (preg_match(‘/.*<meta\s+(.*property\s*=\s*”og:description”\s*.*?)>/i’, $html, $m)) {
$param = $m[1];
if (preg_match(‘/.*content\s*=\s*”(.*?)”.*/i’, $param, $m)) {
$excerpt = $m[1];
}
} else {
if (preg_match(‘/<p>\s*(.*)<\/p>/i’, $html, $m)) {
$excerpt = $m[1];
}
}[/php]

 

同じように「og:image」で画像のURL、「og:site_name」でサイト名が取得できます。

画像はそのまま使う?

OGPで使われる画像は大きいものが多いため、スマートフォンなどで見ているときには通信量が増えてしまいます。

また、画像URLをそのまま直リンクすると、リンク先サイトへの無駄なアクセスも増えてしまうので、そのままは使わないようにしたいです。

この辺はまた次回にでも。

wpdbを使ってDBアクセスしてみた

WordPressプラグインをつくって遊んでます。

リンク先をブログカード風に表示

リンク先を「はてなブログカード」で表示させる「popo-HatenaBlogCard」というのを公開しています。

[link url=”https://popozure.info/20150221/6741″]

「iframe(インラインフレーム)」という仕組みを使って「はてなブログカード」をそのまま表示させています。

見栄えも良いし、表示速度にも問題は無いし、良い事づくしな感じです。

[link url=”http://help.hatenablog.com/entry/blogcards”]

はてなブログカードを表示させるサーバーの能力を間借りして表示させている状態なので、「サービス的に問題無いのかな?」とも思ったのですが、こちらのmbdb(モビデビ)さんの記事を見てみると、はてなさん的にはWordPressとかで使っても問題なさそうな感じです。

[link url=”http://mbdb.jp/hacks/hatenablog-blogcard-ogp-correspondence.html”]

そんなわけで「popo-HatenaBlogCard」は名前のとおり「外部リンクは『はてなブログカード』を表示させて、ついでに内部リンクは似てるけどオリジナル形式で表示させる」プラグインという感じで落ち着こうと思います。

 

とはいえ、やっぱり自前でやってみたくなるものです…Σ(゚ロ゚)o゙

つくりなおし&プラグイン名をつけなおし

「はてなブログカード」は、リンク先を「新しいウィンドウで表示」するようになっていたため、内部リンクの場合でも新しいウィンドウ(タブ)で表示されてしまいました。

このため、内部リンクはオリジナル形式で表示させる機能をつくっていました。

[link url=”https://popozure.info/20150411/7078″]

外部リンクもオリジナル形式で表示させるようにするわけですが、毎回リンク先からタイトルとか本文を取得していると時間がかかってしまいます。

取得した内容を用意したDB(データベース)のテーブルに保管しておいて、次回以降はそこから読み込んで表示するような「キャッシュ」の仕組みを作ります。

 

プラグイン名は「Pz-LinkCard」にする予定です。

プレフィックス(接頭辞)としては「popo-」を使っていましたが、「Pz-」に。

「Pz」は、「ぽぽづれ」的な?発音は「ぴーずぃー」でも「ぴーぜっと」でも「ぽぽづれ」でも。

名称は「ブログカード」でも良かったのですが、ブログ以外もリンクをするのでリンク先をカード形式で表示する「リンクカード」と呼ぼうと思います。(popo-HatenaBlogCardのときも、内部的にはLinkCardと呼んでいたのです。)

DBのテーブルを用意してみる

毎回リンク先から取得すると、サーバー負担をかけてしまうので、「リンク先URLからタイトルや本文などを取得→DBに保存→次回はDBから取得する」という動きにします。

 

プラグインのアクティベーション時にDBのテーブルを作成して、非アクティベーション時に削除をします。

[php title=”pz-linkcard.php” start-line=”71″] register_activation_hook (__FILE__, array($this, ‘Pz_LinkCard_activation’)); // DB作成、パラメータ初期化
register_deactivation_hook (__FILE__, array($this, ‘Pz_LinkCard_deactivation’)); // DB削除[/php]

[php title=”pz-linkcard.php” start-line=”87″]public function Pz_LinkCard_activation() {
global $wpdb;
$sql = “CREATE TABLE pz_linkcard (
id int NOT NULL AUTO_INCREMENT,
url_key varchar(1024) NOT NULL DEFAULT ”,
url varchar(1024) NOT NULL DEFAULT ”,
site_name varchar(256) ,
domain varchar(256) ,
linktype int ,
title varchar(256) ,
excerpt varchar(256) ,
thumbnail varchar(1024) ,
favicon varchar(1024) ,
get_date bigint NOT NULL,
PRIMARY KEY ( id ),
UNIQUE KEY ( id ),
INDEX ( url_key )
) “.$wpdb->get_charset_collate().” ;”;
require_once(ABSPATH . ‘wp-admin/includes/upgrade.php’);
dbDelta($sql);
}[/php]

WordPressに用意されている、データベース操作用の wpdb というクラス関数が用意されています。

DBへのアクセスは、$wpdb におまかせします。

[php title=”pz-linkcard.php” start-line=”88″]global $wpdb;[/php]

$wpdb をグローバル宣言しておかないと使えないので、使う前に書いておきます。

 

DBテーブル作成はSQLコマンドを記述する必要があるようなので、「CREATE TABLE テーブル名 (定義)…」という感じで書いて、dbDelta() を実行します。

MySQL なりのDBMSに直接発行するのでは無く、dbDelta() が解釈するようなので、SQLのコマンドなどは大文字で書く、フィールド名は小文字で書く、とか気をつけるところはあるようです。

[link url=”http://hono-wp.seesaa.net/article/389622476.html”]

 

「id」は更新時のキーにします。「url」はURLを生のまま格納、「url_key」は esc_http() してから格納して検索キーとして使い易くしようと思います。ハッシュ値を使うのも楽しいかもしれません。

「get_time」は更新日時。一定期間を過ぎたら再取得するのに使おうと思います。

 

「charset(文字エンコーディング)」は「CHARSET = utf8」でいいと思ったのですが、「$wpdb->get_charset_collate()」でデフォルトの文字セットが取れるようなので、一応これにしておきました。

 

あとで項目を追加しても、dbDeltaで「CREATE TABLE」を発行すると、今あるテーブルはそのままで、追加したフィールドを最後に追加してくれるような動きをしてくれました。

構文にクセがあるけどDBマイグレーションとか考えなくていいから手軽、という感じでしょうか。

 

非アクティベーション時にテーブルを削除(DROP)します。

[php title=”pz-linkcard.php” start-line=”112″]public function Pz_LinkCard_deactivation() {
global $wpdb;
$sql = “DROP TABLE “.$this->db;
$wpdb->query($sql);
}[/php]

アンインストール時に削除でも良いのですが、お手軽にキャッシュクリアできるようにしておきます。

設定画面からキャッシュしている内容を一覧表示して、選んで更新とか削除ができると良いのだと思いますが、そこまでは知識が追いつきません(^-^;

「カスタム投稿タイプ」を作って、そこにキャッシュしちゃう方法も考えたのですが、どうなんでしょう。

カードの内容をキャッシュ(DB)から取得する

外部リンクの場合は、DB に保存された内容が無いか、「$wpdb->get_row()」を使って検索します。

[php title=”pz-linkcard.php” start-line=”182″] $data = $wpdb->get_row($wpdb->prepare(“SELECT * FROM $this->db WHERE url=%s”, $url));
if (!is_null($data->id) and (time() – $data->get_date < 604800 )) { $title = $data->title;
$excerpt = $data->excerpt;[/php]

URLとかは投稿者が記述するはず、とはいえSQLインジェクションは怖いです。

「$wpdb->prepare()」でプレースホルダー経由でパラメータを渡せるようです。

 

esc_http()でエスケープした文字をキーにしようと思ったのですが、そのままで検索できているので、当面このままで。

 

idがnullじゃなかったら取得できていると見なします。

また、現在日時から604,800秒(60秒×60分×24時間×7日)経過していたら、キャッシュの期限切れとして取得する動きにします。

 

リンク先の情報を取得したら、DBに記録します。

idがnullだったら挿入($wpdb->insert)、nullじゃなかったら更新($wpdb->update)します。

更新のときは、第三パラメータが「where」の指定になるので、キーになる id を指定しています。

id は AUTO_INCREMENT が指定されているので、insert のときに内容をセットしなければ、DBにある一番大きい数値+1で格納してくれます。

[php title=”pz-linkcard.php” start-line=”261″]if (!is_null($data->id)) {
$wpdb->update(
$this->db,
array(
‘url’ => $url,
‘site_name’ => $site_name,
‘domain’ => $domain,
‘linktype’ => $link_type,
‘title’ => $title,
‘excerpt’ => $excerpt,
‘thumbnail’ => $thumbnail_url,
‘get_date’ => time()
),
array(
‘id’ => $data->id
));
} else {
$wpdb->insert(
$this->db,
array(
‘url’ => $url,
‘site_name’ => $site_name,
‘domain’ => $domain,
‘linktype’ => $link_type,
‘title’ => $title,
‘excerpt’ => $excerpt,
‘thumbnail’ => $thumbnail_url,
‘get_date’ => time()
));
}[/php]

リンク先の取得とキャッシュからの取得

リンク先から情報を取得すると、ひとつのリンクカードを作成するのに1.4秒~2秒かかります。

キャッシュ(DB)から取得すると0.0008秒。

内部リンクの処理が0.002秒~0.007秒ほどなので、内部リンクより速いようです。

 

内部リンクがちょっと遅いのはフィルターフックとかで整形しているからだと思うのですが、キャッシュしてしまうと、修正しても反映されなかったりするので、あまり大きなメリットは無さそうに感じます。

 

さて、テキストはキャッシュできましたが、サムネイルとファビコンはDBへ保存するのはちょっと面倒そうです。

やはり外部のWeb APIを使用するのが良さそうです。

 

次の記事では、cURLを使ってOGP情報とかを取得したところを書こうと思います。