PHPのcurl_multiを使って非同期でカウント数を取得するSNSのシェアボタンを自作してみた

目次

先日、CURLというPHPの関数を使ってシェアカウント付のSNSボタンを自作しましたが、スピードがいまいちだったので、他に高速表示できる方法がないか探してみたところ、cURL関数に非同期で値を取得できるcurl_multiという関数があることを知りました。これを使えば複数のcURLハンドルを非同期で実行できるようです。

こんなSNSをボタンを作る

前回、CURLで自作したSNSボタンと同じボタンをcurl_multiを使って作ります。

これを表示するソース

<?php
//カウント数を取得したい対象URL
$targeturl = 'https://www.apple.com/jp/';
$targeturl = urlencode($targeturl);

//現在のページで取得したいとき
//$url = 'https://'.$_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];

// 並列通信用マルチハンドルを用
$mh = curl_multi_init();

// APIごとにCurl Handleを作る
// Twitter
$ch_twitter = curl_init("http://jsoon.digitiminimi.com/twitter/count.json?url=$targeturl");
curl_setopt($ch_twitter, CURLOPT_RETURNTRANSFER, TRUE);
curl_multi_add_handle($mh, $ch_twitter);

// Facebook
$ch_facebook = curl_init("https://graph.facebook.com/?id=$targeturl");
curl_setopt($ch_facebook, CURLOPT_RETURNTRANSFER, TRUE);
curl_multi_add_handle($mh, $ch_facebook);

// Hatena
$ch_hatena = curl_init("https://b.hatena.ne.jp/entry.count?url=$targeturl");
curl_setopt($ch_hatena, CURLOPT_RETURNTRANSFER, TRUE);
curl_multi_add_handle($mh, $ch_hatena);

// Pocket
$ch_pocket = curl_init("https://widgets.getpocket.com/v1/button?v=1&count=horizontal&url=$targeturl&src=$targeturl");curl_setopt($ch_pocket, CURLOPT_RETURNTRANSFER, TRUE);
curl_multi_add_handle($mh, $ch_pocket);

// 複数の通信を非同期で同時実行
do { curl_multi_exec($mh, $running); } while ( $running );

// APIから戻ってきた値を変数に入れる
$json_twitter  = curl_multi_getcontent($ch_twitter);
$json_facebook = curl_multi_getcontent($ch_facebook);
$count_hatena = curl_multi_getcontent($ch_hatena);
$html_pocket = curl_multi_getcontent($ch_pocket);

//cURLハンドルセットを閉じる
curl_multi_remove_handle($mh, $ch_twitter)
curl_close($ch_twitter);
curl_multi_remove_handle($mh, $ch_facebook);
curl_close($ch_facebook);
curl_multi_remove_handle($mh, $ch_hatena);
curl_close($ch_hatena);
curl_multi_remove_handle($mh, $ch_pocket);
curl_close($ch_pocket);
curl_multi_close($mh);

/*デバッグ用
var_dump($json_twitter)."\n";
var_dump($json_facebook)."\n"
var_dump($count_hatena)."\n";
var_dump($html_pocket)."\n";
*/

//Twitterのカウント数を取り出す
$count_twtter = json_decode($json_twitter, true );
$count_twtter = num_format(strval($count_twtter['count']));

//facebookのカウント数を取り出す
$count_facebook = json_decode($json_facebook, true );
$count_facebook = num_format($count_facebook['share']['share_count']);

//Hatenaのカウント数を取り出す
$count_hatena = num_format($count_hatena);

//Pocketのカウント数を取り出す
//HTML→DOM→XML→JSON→配列に変換
$dom_pocket = new DOMDocument('1.0', 'UTF-8');
$dom_pocket->preserveWhiteSpace = false;
$dom_pocket->loadHTML($html_pocket);
$xmlString_pocket = $dom_pocket->saveXML();
$xmlObject_pocket = simplexml_load_string($xmlString_pocket);
$count_pocket = json_decode(json_encode($xmlObject_pocket), true);
$count_pocket = num_format(strval($count_pocket['body']['div']['a']['span']['em']))
?>

<!DOCTYPE html>
  <html lang="ja" itemscope itemtype="http://schema.org/WebPage">
  <head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-dns-prefetch-control" content="on">
<link rel="dns-prefetch" href="//cdn.jsdelivr.net"> <style> .sns-counter {< width: 100%; } .sns-counter li { display: inline-block; border-radius: 2px; width: 80px; padding: 3px; margin-left: 3px; } .sns-counter li span { display: inline-block; text-align: center; width: 70%; font-size: 12px; font-weight: bold; color: #fff; } .sns-counter li i { display: inline-block; text-align: center; width: 30%; color: #fff; font-size: 14px; position: relative; top: 1px; } .sns-counter .btn-tw { background-color: #55ACEE; } .sns-counter .btn-fb { background-color: #3A5795; } .sns-counter .btn-hb { background-color: #008CE1; } .sns-counter .btn-pk { background-color: #ef4357; } .sns-counter .btn-line { background-color: #1dcd00; } .sns-counter .btn-total { background-color: #000; } .btn-hb:hover,.btn-tw:hover,.btn-fb:hover,.btn-pk:hover,.btn-line:hover,.btn-total:hover { background-color: #ccc; }< i.fa-hatena:before { content: "B!"; font-family: Verdana; font-weight: bold; } </style> </head> <body> <div> <ul class="sns-counter" title="<?php echo $targeturl; ?>"><!-- --><li class="btn-tw"> <a href="//twitter.com/intent/tweet?url=<?php echo $targeturl; ?>" target="_blank"> <i class="fab fa-twitter"></i><span><?php echo $count_twtter; ?></span> </a>
</li><!-- --><li class="btn-fb"> <a href="//www.facebook.com/sharer/sharer.php?u=<?php echo $targeturl; ?>" onclick="window.open('https://www.facebook.com/sharer/sharer.php?u=<?php echo $targeturl; ?>', 'new', 'width=500,height=300');return false;" target="_blank"> <i class="fab fa-facebook-f"></i><span><?php echo $count_facebook; ?></span> </a> </li><!-- --><li class="btn-hb"> <a href="//b.hatena.ne.jp/entry/<?php echo $targeturl; ?>" target="_blank"> <i class="fa fa-hatena"></i><span><?php echo $count_hatena; ?></span> </a> </li><!-- --><li class="btn-pk"> <a href="//getpocket.com/edit?url=<?php echo $targeturl; ?>" target="_blank"> <i class="fab fa-get-pocket"></i><span><?php echo $count_pocket; ?></span> </a> </li><!-- --><li class="btn-line"> <a href="//social-plugins.line.me/lineit/share?url=<?php echo $targeturl; ?>" target="_blank"> <i class="fab fa-line"></i><span>LINE</span> </a> </li> </ul> </div> <script> window.addEventListener("load",function(){ const css=[ "//cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/all.min.css" ]; for(i in css){ let html=document.createElement("link"); html.rel="stylesheet";html.href=css[i]; html.async=true;document.head.appendChild(html); } }); </script> </body> </html>

たった0.5秒だけど速い!

前回平均2秒だったのが今回1.5秒になりました。

期待していたのは1秒以下だったのですが、curl_multiを使った効果はありました。非同期なのはAPIから結果を取得しに行く部分で、表示は非同期ではありません。よってブログのページにこのボタンを埋め込むとこの1.5秒分ほどページ全体の表示を遅くさせる可能性があります。それでも純正のシェアボタンを使うよりは速いと思います。

表示も非同期にしたいときはPHPでカウント数を呼び出す部分をJavascriptから実行させることができれば可能かもしれません。jQueryでできるらしいので今度試してみたいと思います。

2019/01/17追記

jQueryから非同期でPHPを実行する方法をやってみました。

参考サイト

301 moved permanently

301 moved permanently

http://php.net/manual/ja/ref.curl.php

404 not found

404 not found

http://asklife.info/archives/3335

phpのcurlをcurl_multiで複数同時に実行する方法 | minory

phpのcurlをcurl_multiで複数同時に実行する方法 | minory

https://minory.org/php-curl_multi.html

apiとの通信効率をよくする実装例(1) curl_multi - yahoo! japan tech blog

apiとの通信効率をよくする実装例(1) curl_multi - yahoo! japan tech blog

https://techblog.yahoo.co.jp/architecture/api1_curl_multi/

前へ

PHPでカウント付のSNSシェアボタンを自作してみた

次へ

jQueryのAjaxからカウント数付のソーシャルボタンを出力するPHPを非同期で実行する