1 <?php
2
3 function getContents($file, $default = '') {
4 if (!is_file($file) || !($contents = @file_get_contents($file)))
5 return $default;
6 else
7 return trim($contents);
8 }
9
10 /**
11 * Deal with pci.ids and usb.ids workings
12 * @author Joe Gillotti
13 */
14 class HW_IDS {
15
16 private
17 $_usb_file = '/usr/share/misc/usb.ids',
18 $_pci_file = '/usr/share/misc/pci.ids',
19 $_cache_file = '',
20 $_existing_cache_vals = array(),
21 $_usb_entries = array(),
22 $_pci_entries = array(),
23 $_usb_devices = array(),
24 $_pci_devices = array();
25
26 /**
27 * Constructor
28 */
29 public function __construct() {
30 $this->_cache_file = dirname(__FILE__).'/cache.json';
31 $this->_populate_cache();
32 }
33
34 /**
35 * Run the cache file
36 */
37 private function _populate_cache() {
38 if (function_exists('json_decode') && is_readable($this->_cache_file))
39 $this->_existing_cache_vals = (array) @json_decode(getContents($this->_cache_file, ''), true);
40 }
41
42 /**
43 * Get the USB ids from /sys
44 */
45 private function _fetchUsbIds() {
46 $usb_paths = (array) @glob('/sys/bus/usb/devices/*/uevent', GLOB_NOSORT);
47 $num_usb_paths = count($usb_paths);
48 for ($i = 0; $i < $num_usb_paths; $i++) {
49 $path = $usb_paths[$i];
50 if (is_readable($path) && preg_match('/^product=([^\/]+)\/([^\/]+)\/[^$]+$/m', strtolower(getContents($path)), $match) == 1) {
51 $this->_usb_entries[str_pad($match[1], 4, '0', STR_PAD_LEFT)][str_pad($match[2], 4, '0', STR_PAD_LEFT)] = 1;
52 }
53 }
54 }
55
56 /**
57 * Get the PCI ids from /sys
58 */
59 private function _fetchPciIds() {
60 $pci_paths = (array) @glob('/sys/bus/pci/devices/*/uevent', GLOB_NOSORT);
61 $num_pci_paths = count($pci_paths);
62 for ($i = 0; $i < $num_pci_paths; $i++) {
63 $path = $pci_paths[$i];
64 if (is_readable($path) && preg_match('/pci\_(?:subsys_)?id=(\w+):(\w+)/', strtolower(getContents($path)), $match) == 1) {
65 $this->_pci_entries[$match[1]][$match[2]] = 1;
66 }
67 else {
68 $path = dirname($path);
69 $vendor = getContents($path.'/subsystem_vendor', false);
70 $device = getContents($path.'/subsystem_device', false);
71 if ($vendor !== false && $device !== false) {
72 $vendor = str_pad(strtoupper(substr($vendor, 2)), 4, '0', STR_PAD_LEFT);
73 $device = str_pad(strtoupper(substr($device, 2)), 4, '0', STR_PAD_LEFT);
74 $this->_pci_entries[$vendor][$device] = 1;
75 }
76 }
77 }
78 }
79
80 /**
81 * Use the pci.ids file to translate the ids to names
82 */
83 private function _fetchPciNames() {
84 for ($v = false, $file = @fopen($this->_pci_file, 'r'); $file != false && $contents = fgets($file);) {
85 if (preg_match('/^(\S{4})\s+([^$]+)$/', $contents, $vend_match) == 1) {
86 $v = $vend_match;
87 }
88 elseif(preg_match('/^\s+(\S{4})\s+([^$]+)$/', $contents, $dev_match) == 1) {
89 if($v && isset($this->_pci_entries[strtolower($v[1])][strtolower($dev_match[1])])) {
90 $this->_pci_devices[$v[1]][$dev_match[1]] = array('vendor' => rtrim($v[2]), 'device' => rtrim($dev_match[2]));
91 }
92 }
93 }
94 $file && @fclose($file);
95 }
96
97 /**
98 * Use the usb.ids file to translate the ids to names
99 */
100 private function _fetchUsbNames() {
101 for ($v = false, $file = @fopen($this->_usb_file, 'r'); $file != false && $contents = fgets($file);) {
102 if (preg_match('/^(\S{4})\s+([^$]+)$/', $contents, $vend_match) == 1) {
103 $v = $vend_match;
104 }
105 elseif(preg_match('/^\s+(\S{4})\s+([^$]+)$/', $contents, $dev_match) == 1) {
106 if($v && isset($this->_usb_entries[strtolower($v[1])][strtolower($dev_match[1])])) {
107 $this->_usb_devices[$v[1]][$dev_match[1]] = array('vendor' => rtrim($v[2]), 'device' => rtrim($dev_match[2]));
108 }
109 }
110 }
111 $file && @fclose($file);
112 }
113
114 /**
115 * Decide if the cache file is sufficient enough to not parse the ids files
116 */
117 public function _is_cache_worthy() {
118 $pci_good = true;
119 foreach(array_keys($this->_pci_entries) as $vendor) {
120 foreach (array_keys($this->_pci_entries[$vendor]) as $dever) {
121 if (!isset($this->_existing_cache_vals['hw']['pci'][$vendor][$dever])) {
122 $pci_good = false;
123 break 2;
124 }
125 }
126 }
127 $usb_good = true;
128 foreach(array_keys($this->_usb_entries) as $vendor) {
129 foreach (array_keys($this->_usb_entries[$vendor]) as $dever) {
130 if (!isset($this->_existing_cache_vals['hw']['usb'][$vendor][$dever])) {
131 $usb_good = false;
132 break 2;
133 }
134 }
135 }
136 return array('pci' => $pci_good, 'usb' => $usb_good);
137 }
138
139 /*
140 * Write cache file with latest shit
141 */
142 public function _write_cache() {
143 if (function_exists('json_encode'))
144 @file_put_contents($this->_cache_file, json_encode(array(
145 'hw' => array(
146 'pci' => $this->_pci_devices,
147 'usb' => $this->_usb_devices
148 )
149 )));
150 }
151
152 /**
153 * Do its goddam job
154 */
155 public function work() {
156 $this->_fetchPciIds();
157 $this->_fetchUsbIds();
158 $worthiness = $this->_is_cache_worthy();
159 $save_cache = false;
160 if (!$worthiness['pci']) {
161 $save_cache = true;
162 $this->_fetchPciNames();
163 }
164 else
165 $this->_pci_devices = $this->_existing_cache_vals['hw']['pci'];
166 if (!$worthiness['usb']) {
167 $save_cache = true;
168 $this->_fetchUsbNames();
169 }
170 else
171 $this->_usb_devices = $this->_existing_cache_vals['hw']['usb'];
172 if ($save_cache)
173 $this->_write_cache();
174 }
175
176 /**
177 * Get results
178 */
179 public function result() {
180 return array(
181 'pci' => $this->_pci_devices,
182 'usb' => $this->_usb_devices
183 );
184 }
185 }
186
187 $hw = new HW_IDS;
188 $hw->work();
189 var_dump($hw->result());