PHPで CPU情報を取得(Windowsアプリ版)

(1/1)
2018 年(平成 30 年)の年明け早々、Intel 系 CPU に重大な脆弱性があるとの噂が流れ、Intel は正式に「Meltdown」「Spectre」という 2 つの脆弱性があることを公表した。
Microsoft などベンダ各社は、この脆弱性への provision パッチを公開しているが、厄介なことに、CPU の世代によっては、動作が遅くなったり、再起動してしまう現象が報告されている。
そこで今回は、どの世代の CPU なのか、情報を取得・表示する Windows アプリを作ってみることにする。

(2020 年 8 月 1 日)CPU 情報ファイルを更新。

サンプル・プログラム

PHPでWindowsアプリ開発:CPU情報を取得

解説:CPU情報ファイル

0033: //CPU情報ファイル : オンライン
0034: define('PAHOO_PROCESSOR_LIST', 'http://www.pahoo.org/db/xml/processorList.xml');
0035: //CPU情報ファイル : ローカル
0036: define('LOCAL_PROCESSOR_LIST', 'processorList.xml');

CPU のベンダ名、アーキテクチャなどの情報を、XML ファイル "processorList.xml" に用意しておく。
これは、当サイトにある最新ファイルを参照するようにしているが、オンライン接続できない場合はローカルにあるファイルを参照するようにしている。
プログラムを実行すると、ウィンドウの右下に "(online:2018/01/25)" と表示されていたら、オンラインで当サイトの 2018 年(平成 30 年)1 月 25 日の情報ファイルを読み込んでいることを示す。
"(local:2018/01/21)" ならば、ローカルにある 2018 年(平成 30 年)1 月 21 日の情報ファイルを読み込んでいる。
"*error*" だと、CPU 情報ファイルが見つからないことを意味する。

もし最新 CPU をお持ちで正しい情報が表示されないようだったら、投稿コーナーへメッセージをお願いしたい。

解説:NativeSystemInfo Function

0165: /**
0166:  * NativeSystemInfoを取得
0167:  * @param array  $sysinfo NativeSystemInfoを格納する配列
0168:  * @return bool TRUE:取得成功/FALSE:失敗
0169: */
0170: function GetNativeSystemInfo(&$sysinfo) {
0171: //GetNativeSystemInfo function : msdn
0172: //https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms724340(v=vs.85).aspx
0173: 
0174: //SYSTEM_INFO structure : msdn
0175: //https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms724958(v=vs.85).aspx
0176:     define('SYSTEM_INFO', 'VdwOemId/VdwPageSize/VlpMinimumApplicationAddress/VlpMaximumApplicationAddress/VdwActiveProcessorMask/VdwNumberOfProcessors/VdwProcessorType/VdwAllocationGranularity/vwProcessorLevel/vwProcessorRevision');
0177:     define('SYSTEM_INFO_RAW', "V8v2");
0178:     define('SYSTEM_INFO_SIZE', 8 * 4 + 2 * 2);
0179: 
0180:     static $Kernel = NULL;
0181:     static $GetNativeSystemInfo = NULL;
0182: 
0183:     //Kernel32.dll
0184:     if ($Kernel == NULL) {
0185:         $Kernel = wb_load_library('Kernel');
0186:     }
0187:     if ($Kernel == NULL)    return FALSE;
0188: 
0189:     //GetNativeSystemInfo function
0190:    if ($GetNativeSystemInfo == NULL) {
0191:         $GetNativeSystemInfo = wb_get_function_address('GetNativeSystemInfo', $Kernel);
0192:     }
0193:     if ($GetNativeSystemInfo == NULL)   return FALSE;
0194: 
0195:     $val = pack(SYSTEM_INFO_RAWSYSTEM_INFO_SIZE, 0,0,0,0,0,0,0,0,0);
0196:     wb_call_function($GetNativeSystemInfoarray($val));
0197:     $arr = unpack(SYSTEM_INFO$val);
0198:     if (!isset($arr['dwOemId']))    return FALSE;
0199: 
0200:     //データの複写
0201:     foreach ($arr as $key=>$val)    $sysinfo[$key] = $val;
0202:     return TRUE;
0203: }

CPU 情報を取り出すのに、Win32APIGetNativeSystemInfo Function を利用する。Win32API の呼び出し方は、「PHP でクリップボードにテキスト貼り付け」で説明したとおりだ。

この API は引数なしで、CPU 情報を格納した構造体 SYSTEM_INFO を返す。SYSTEM_INFO の構造は、SYSTEM_INFO structure の通りである。
Win32API では、構造体がバイナリデータとして渡されるので、あらかじめ  pack  を使って構造体 SYSTEM_INFO を変数 $val に定義しておく。
wb_call_function を使って GetNativeSystemInfo を呼び出したら、今度は  unpack  を使い、構造体を配列 $arr に展開する。あらかじめ文字列 SYSTEM_INFO を用意しておくことで、受け取ったバイナリデータを構造体の形に合わせて連想配列に格納していく。

解説:CPU情報リストを取得する

0205: /**
0206:  * CPU情報リストを取得する
0207:  * @param  array  $processorList CPU情報リストを格納する配列
0208:  * @return int 2:オンラインから取得,1:ローカルから取得,0:取得失敗
0209: */
0210: function getProcessorList(&$processorList) {
0211:     $res = 0;
0212: 
0213:     //XML読み込み
0214:     $options = array('parseAttributes' => TRUE);
0215:     $xml = new XML_Unserializer($options);
0216: 
0217:     //CPU情報リスト : pahoo.org
0218:     $xml_data = @file_get_contents(PAHOO_PROCESSOR_LIST);
0219:     if ($xml_data) {
0220:         $xml->unserialize($xml_dataFALSE);
0221:         $processorList = $xml->getUnserializedData();
0222:         $res = 2;
0223:     //CPU情報リスト : ローカル
0224:     } else {
0225:         $xml_data = @file_get_contents(LOCAL_PROCESSOR_LIST);
0226:         if ($xml_data) {
0227:             $xml->unserialize($xml_dataFALSE);
0228:             $processorList = $xml->getUnserializedData();
0229:             $res = 1;
0230:         }
0231:     }
0232:     unset($xml);
0233: 
0234:     //レスポンス・チェック
0235:     if (! isset($processorList['processor'])) $res = 0;
0236: 
0237:     return $res;
0238: }

前述の CPU 情報リストを読み込むのが、getProcessorList である。

解説:CPU情報を取得

0240: /**
0241:  * NativeSystemInfoの結果とCPU情報リストをマッチングしCPU情報を取得
0242:  * @param   array  $sysinfo NativeSystemInfo
0243:  * @param   array  $processorList CPU情報リスト
0244:  * @param   array  $items CPU情報を格納する配列
0245:  * @return  bool TRUE:取得成功/FALSE:取得失敗
0246: */
0247: function getProcessorInfo($sysinfo$processorList, &$items) {
0248:     $items['level']    = (int)$sysinfo['wProcessorLevel'];
0249:     $items['type']     = (int)$sysinfo['dwProcessorType'];
0250:     $items['number']   = (int)$sysinfo['dwNumberOfProcessors'];
0251:     $items['model']    = (int)$sysinfo['wProcessorRevision'] >> 8;
0252:     $items['stepping'] = (int)$sysinfo['wProcessorRevision'] & 0x00FF;
0253:     $items['vendor']   = 'unknown';
0254:     $items['architecture'] = 'unknown';
0255: 
0256:     //マッチング
0257:     foreach ($processorList['processor'] as $processor) {
0258:         if (($items['level'] == hexdec($processor['family'])) && ($items['model'] == hexdec($processor['model']))) {
0259:             $items['vendor'] = $processor['vendor'];
0260:             $items['architecture'] = $processor['architecture'];
0261:             break;
0262:         }
0263:     }
0264: }

GetNativeSystemInfogetProcessorList の内容をマッチングし、必要な CPU 情報を配列に格納するのが getProcessorInfo である。

その他、クリップボードへのコピー機能は、「PHP でクリップボードにテキスト貼り付け(Windows アプリ版)」で紹介したプログラムを流用している。

コンパイル

コマンドラインから "bamcompile cpuid.bcp" を実行する。コンパイルが完了すると、"cpuid.exe" が生成される。"cpuid.exe" は、DLL 不要で、単独で動作する EXE プログラムである。

なお、ダウンロードした圧縮ファイルを解凍すると、"cpuid.exe" のあるフォルダに "getProcessorList.xml" が解凍される。これが CPU 情報リストで、内容を編集することで最新 CPU の情報も正しく表示できるようになる。

参考サイト

(この項おわり)
header