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/fontawesome-free@5.6.3/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を実行する方法をやってみました。

参考サイト

php: curl 関数 - manual

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

phpで複数apiを叩く並列処理を実装 – asklife

http://asklife.info/archives/3335

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

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

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

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

前へ

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

次へ

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