PHPでワードクラウドをつくる

(1/1)
ワードクラウド
ワードクラウド(word cloud)とは、与えられたコンテンツを解析し、上図のように出現頻度が高い単語ほど大きく表示する仕組みである。
今回は、与えられたURLのワードクラウドを表示するプログラムをPHPで作ってみることにする。
(2025年9月19日).pahooEnv導入

目次

サンプル・プログラム

圧縮ファイルの内容
WordCloud.phpサンプル・プログラム本体。
.pahooEnvクラウドサービスを利用するためのアカウント情報などを記入する .env ファイル。
使い方は「各種クラウド連携サービス(WebAPI)の登録方法」を参照。include_path が通ったディレクトリに配置すること。
pahooInputData.phpデータ入力に関わる関数群。
使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。
WordCloud.php 更新履歴
バージョン 更新日 内容
2.2.0 2023/12/16 日本語形態素解析V2対応
2.1 2021/10/02 PHP8対応,リファラチェック改良
2.1 2017/04/09 PHP7対応
2.0 2014/08/02 大幅改訂
1.1 2009/06/20 chunked対応、ぱふぅ家のホームページ以外に対応
pahooInputData.php 更新履歴
バージョン 更新日 内容
2.0.1 2025/08/11 getParam() bug-fix
2.0.0 2025/08/11 pahooLoadEnv() 追加
1.9.0 2025/07/26 getParam() 引数に$trim追加
1.8.1 2025/03/15 validRegexPattern() debug
1.8.0 2024/11/12 validRegexPattern() 追加

準備:PHP の https対応

クラウド連携や相手先サイトのデータを読み込むのに https通信を使うため、PHPに OpenSSLモジュールが組み込まれている必要がある。関数  phpinfo  を使って、下図のように表示されればOKだ。
OpenSSL - PHP
そうでない場合は、次の手順に従ってOpenSSLを有効化し、PHPを再起動させる必要がある。

Windowsでは、"php.ini" の下記の行を有効化する。
extension=php_openssl.dll
Linuxでは --with-openssl=/usr オプションを付けて再ビルドする。→OpenSSLインストール手順

これで準備は完了だ。

準備:pahooInputData 関数群

PHPのバージョンや入力データのバリデーションなど、汎用的に使う関数群を収めたファイル "pahooInputData.php" が同梱されているが、include_path が通ったディレクトリに配置してほしい。他のプログラムでも "pahooInputData.php" を利用するが、常に最新のファイルを1つ配置すればよい。

また、各種クラウドサービスに登録したときに取得するアカウント情報、アプリケーションパスワードなどを登録した .pahooEnv ファイルから読み込む関数 pahooLoadEnv を備えている。こちらについては、「各種クラウド連携サービス(WebAPI)の登録方法」をご覧いただきたい。

必要な機能

このプログラムでは、大きく3つの機能が要求される。
  1. URLからコンテンツを取り出す。
  2. コンテンツから単語を切り出し、出現頻度を数える。
  3. 出現頻度の高い単語ほど大きく表示する。
1.は、後述する myGetContents 関数によって実現する。2.は、「PHPで形態素解析を行う」で使ったYahoo!JAPANのWebAPI「日本語形態素解析」をそのまま利用する。
3.は、後述する 関数によって実現する。

準備:初期値など

WordCloud.php

  64: // 初期値(START) =============================================================
  65: 
  66: // 表示幅(ピクセル)
  67: define('WIDTH', 600);
  68: 
  69: // -- 以下のデータは .env ファイルに記述可能
  70: // Yahoo! JAPAN Webサービス アプリケーションID【各自で設定】
  71: // 取得方法:https://www.pahoo.org/e-soul/webtech/php06/php06-01-02.shtm#Yahoo
  72: if (isset($_ENV['PAHOO_YAHOO_APPLICATION_ID'])) {
  73:     define('YAHOO_APPLICATION_ID', $_ENV['PAHOO_YAHOO_APPLICATION_ID']);
  74: else {
  75:     define('YAHOO_APPLICATION_ID', '');
  76: }
  77: 
  78: // リクエストURL【変更不可】
  79: define('YAHOO_MAService_URL', 'https://jlp.yahooapis.jp/MAService/V2/parse');
  80: 
  81: // ワードクラウドを表示するときの最大フォントサイズ(%)
  82: define('MAX_FONT_SIZE', 250);
  83: // ワードクラウドを表示するときの最小フォントサイズ(%)
  84: define('MIN_FONT_SIZE', 80);
  85: 
  86: // リンク先の検索対象ドメイン名
  87: define('SEARCH_DOMAIN', 'pahoo.org');
  88: 
  89: // サンプルURL
  90: define('DEF_URL', 'https://www.pahoo.org/e-soul/webtech/php01/php01-01.shtm');
  91: 
  92: // 初期値(END) ===============================================================

Yahoo!JAPANのWebAPI「日本語形態素解析」を利用するため、Yahoo! JAPAN Webサービス アプリケーションID を取得する必要がある。その入手方法は「Yahoo!JAPAN デベロッパーネットワーク - WebAPIの登録方法」を参照されたい。
取得したIDは、.pahooEnv ファイルに記入するか、定数 APPLICATION_ID に格納する。

解説:ワードクラウドの作成

WordCloud.php

 275: /**
 276:  * ワードクラウドを作成する
 277:  * @param   array  $items 情報を格納した配列
 278:  * @return  string ワードクラウド(HTML)
 279: */
 280: function getWordCloud($items) {
 281:     $outstr = '';
 282:     $n = 0;
 283: 
 284:     // 出現頻度の最大値・最小値を調べる
 285:     $countMax = 0;
 286:     $countMin = 0;
 287:     foreach ($items as $surface=>$val) {
 288:         if (isDisplayWord($surface, $val['pos'])) {
 289:             if ($val['count'> $countMax)      $countMax = $val['count'];
 290:             if ($val['count'< $countMin)       $countMin = $val['count'];
 291:         }
 292:     }
 293:     $k = (MAX_FONT_SIZE - MIN_FONT_SIZE) / ($countMax - $countMin);
 294: 
 295:     foreach ($items as $surface=>$val) {
 296:         if (isDisplayWord($surface, $val['pos'])) {
 297:             $n++;
 298:             $count = $val['count'];
 299:             $fsize = (int)($k * $val['count'+ MIN_FONT_SIZE);
 300:             if ($fsize < MIN_FONT_SIZE)      $fsize = MIN_FONT_SIZE;
 301:             if ($fsize > MAX_FONT_SIZE)     $fsize = MAX_FONT_SIZE;
 302:             $link = getLink($surface);
 303:             if ($n > 1)     $outstr .",\n";
 304: $outstr .=<<< EOT
 305: <span style="font-size: {$fsize}%;">
 306: <a href={$link}>{$surface}</a>
 307: </span>
 308: 
 309: EOT;
 310:         }
 311:     }
 312:     return $outstr;
 313: }

ユーザー関数 getWordCloudワードクラウドを作成する。

ある単語の表示フォントサイズ(%) $ S_n $ は下記の計算式で算出する。
$$ S_n = k C_n + S_{min} \] \[ k = \frac{S_{max} - S_{min}}{C_{max} - C_{min}} $$
$ S_{max} $ ‥‥最小表示フォントサイズ(%)
$ S_{min} $ ‥‥最大表示フォントサイズ(%)
$ C_{max} $ ‥‥単語の最大出現回数
$ C_{min} $ ‥‥単語の最小出現回数
$ C_n $ ‥‥ある単語の出現回数

WordCloud.php

 239: /**
 240:  * ワードクラウド表示時における個々の単語のリンク先URLを取得する
 241:  * @param   string $surface 見出し語
 242: */
 243: function getLink($surface) {
 244:     $url  = 'https://www.google.com/search?hl=ja&lr=lang_ja&q=';    // Google検索
 245:     $site = SEARCH_DOMAIN;      // 検索絞り込みドメイン名
 246: 
 247:     return $url . urlencode($surface. '+site%3A' . $site;
 248: }

ただ文字サイズを変更して並べるだけでは面白くないので、個々の単語にリンクを張ることにした。
ここでは、その単語をGoogle検索に投げ、その際に site で絞り込み検索を指定するようにした。$site には自サイトのURLを入れておけばいいだろう。

解説:コンテンツの取り出し

WordCloud.php

 155: /**
 156:  * コンテンツの必要な部分を読み込む
 157:  * @param   string $url コンテンツのURL
 158:  * @return  string 読み込んだコンテンツ/FALSE=失敗
 159: */
 160: function myGetContents($url) {
 161:     $instr = @file_get_contents($url);
 162:     $instr = mb_convert_encoding($instr, INTERNAL_ENCODING, 'auto');
 163:     if ($instr == FALSE || $instr == '')    return FALSE;
 164: 
 165:     // scriptを除く
 166:     $arr = array();
 167:     $ss = preg_match('/\<body.*?\>(.*?)<\/body\>/imsu', $instr, $arr);
 168:     $ss = preg_replace('/\<script.*?\>.*?<\/script\>/imsu', '', $arr[1]);
 169:     $ss = preg_replace('/\<style.*?\>.*?<\/style\>/imsu', '', $ss);
 170:     $ss = preg_replace('/\&nbsp\;/imsu', '', $ss);      // &nbsp;を除く
 171:     $ss = strip_tags($ss);                              // タグを除く
 172:     $ss = html_entity_decode($ss);          // 特殊文字を通常文字に変換
 173:     $outstr = preg_replace('/\n|\r|\r|\t/', '', $ss);   // 改行、タブを除く
 174: 
 175:     return $outstr;
 176: }

ユーザー関数 getParse に渡すコンテンツをURLから取り出す必要がある。これには少し工夫が必要だ。
まず、URLの全体を getParse に渡すのは非合理的だ。ヘッダやフッタなど、コンテンツとして分析する必要がない部分も含まれてしまう。
そこで用意したのがユーザー関数 myGetContents である。

まず、関数  file_get_contents  を使ってコンテンツ全体を変数 $instr に取り込む。
次に、 preg_match  を使って、<body> タグ内だけ切り出す。
続いて、<script> タグや<style> タグ内は省く。特殊文字 &nbsp; 無視する。
最後に、関数  strip_tags 、 html_entity_decode 、 preg_replace  を使い、HTMLやPHPのタグ、特殊文字、改行・タブなどを消去しておく。

ユーザー関数 my_get_contents については、解析したサイトの状況に合わせて変更してほしい。

質疑応答

【質問】かんちゃん 2023/12/11
define('REFER_ON', '');
アプリケーションIDを入力し、リンク先ドメイン名を入力サンプルURLをワードクラウドを作りたいページにし、以上の変更を加えたのに、上記の結果に。
まだほかに修正する個所があるのでしょうか
【回答】
プログラムが使用しているYahoo!JAPANのWebAPI「日本語形態素解析」がバージョンアップし、旧バージョンは使用できなくなりました。プログラムを新しいバージョンに対応させましたので、お試しください。
また、アプリケーションエラーを表示したときは、プログラム冒頭にある FLAG_RELEASE の定義を
 define('FLAG_RELEASE', FALSE);
としていただくことで、詳しいエラーを表示するようになります。

参考サイト

(この項おわり)
header