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