/[drupal]/contributions/modules/browscap/browscap.module
ViewVC logotype

Contents of /contributions/modules/browscap/browscap.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.6 - (show annotations) (download) (as text)
Thu Apr 13 15:49:30 2006 UTC (3 years, 7 months ago) by unconed
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5
Changes since 1.5: +2 -2 lines
File MIME type: text/x-php
#5371: tablesort_pager removal
- Fix some badly tagged modules
1 <?php
2 // $Id: browscap.module,v 1.5 2006/01/05 20:01:00 deekayen Exp $
3
4 /**
5 * @file
6 * Replacement for PHP's get_browser() function
7 */
8
9 /**
10 * Implementation of hook_help().
11 */
12 function browscap_help($section) {
13 switch ($section) {
14 case 'admin/modules#description':
15 return t('Provides statistics on browsers, and a replacement for '.
16 "PHP's get_browser() function.");
17 }
18 }
19
20 function browscap_get_browser($useragent = NULL, $return_array = FALSE) {
21 if (!$useragent) {
22 $useragent = $_SERVER['HTTP_USER_AGENT'];
23 }
24 // Cache the results
25 $cacheid = 'browscap:'.$useragent;
26 $cache = cache_get($cacheid);
27 if ((!empty($cache)) and ($cache->created > time() - 60*60*24)) {
28 // Found a fresh entry in the cache
29 $browserinfo = unserialize($cache->data);
30 } else {
31 // Note the 'backwards' use of LIKE - the useragent column contains
32 // the wildcarded pattern to match against our full-length string
33 // The ORDER BY chooses the most-specific matching pattern
34 $browserinfo = db_fetch_object(db_query_range(
35 "SELECT * from {browscap} WHERE '%s' LIKE useragent ORDER BY LENGTH(useragent) DESC",
36 $useragent, 0, 1));
37 // A couple of fieldnames not in our database, provided for
38 // compatibility with PHP's get_browser()
39 $browserinfo->browser_name_pattern = strtr($browserinfo->useragent, '%_', '*?');
40 $browserinfo->tables = $browserinfo->htmltables;
41 cache_set($cacheid, serialize($browserinfo));
42 }
43
44 if ($return_array) {
45 return get_object_vars($browserinfo);
46 } else {
47 return $browserinfo;
48 }
49 }
50
51 /**
52 * Implementation of hook_cron().
53 */
54 function browscap_cron() {
55 // Has it been a week since the last (attempt to) import?
56 $last_imported = variable_get('browscap_imported', 0);
57 if (($last_imported + 60*60*24*7) < time()) {
58 _browscap_import();
59 variable_set('browscap_imported', time());
60 }
61 }
62
63 // A numeric interpretation of browscap.csv's TRUE/FALSE/default fields
64 function _browscap_boolean($value) {
65 switch ($value) {
66 case 'TRUE':
67 case 'true':
68 return 1;
69 case 'FALSE':
70 case 'false':
71 case 'default':
72 default:
73 return 0;
74 }
75 }
76
77 /**
78 * If there's a new version of browscap.csv, fetch it and update the
79 * database.
80 */
81 function _browscap_import() {
82 // Politely check the version for updates before fetching the file
83 $versionpage = drupal_http_request('http://www.garykeith.com/browsers/version.asp');
84 if ($versionpage->error) {
85 watchdog('browscap', "Couldn't check version: ".$versionpage->error);
86 return;
87 }
88 $browscapversion = trim($versionpage->data);
89 $oldversion = variable_get('browscap_version', 'Never fetched');
90 if ($browscapversion == $oldversion) {
91 // No update, nothing to do here
92 watchdog('browscap', 'No new version of browscap to import');
93 return;
94 }
95
96 // Fetch the new version, and dump it in the temp directory
97 $server = $_SERVER['SERVER_NAME'];
98 $path = variable_get('file_directory_temp', '/tmp');
99 $browscapfile = "$path/browscap_$server.csv";
100
101 // If we can, download the zipped version and extract the file
102 if (is_callable('zip_open')) {
103 $browscapzipfile = "$path/csv_browscap_$server.zip";
104 $browscapzip = drupal_http_request('http://www.garykeith.com/browsers/stream.asp?CSV_BrowsCapZIP');
105 if ($browscapzip->error or !trim($browscapzip->data)) {
106 watchdog('browscap', "Couldn't retrieve updated browscap: ".$browscapzip->error);
107 return;
108 }
109 $browscapzipfp = fopen($browscapzipfile, "w");
110 fwrite($browscapzipfp, $browscapzip->data);
111 fclose($browscapzipfp);
112 $zip = zip_open($browscapzipfile);
113 if ($zip) {
114 while ($zip_entry = zip_read($zip)) {
115 if (zip_entry_name($zip_entry) == 'browscap.csv') {
116 if (zip_entry_open($zip, $zip_entry, 'rb')) {
117 $browscapfp = fopen($browscapfile, 'w');
118 fwrite($browscapfp, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)));
119 fclose($browscapfp);
120 break;
121 }
122 }
123 }
124 zip_close($zip);
125 }
126 unlink($browscapzipfile);
127 // Can't handle zip, get the unzipped version
128 } else {
129 $browscap = drupal_http_request('http://www.garykeith.com/browsers/stream.asp?BrowsCapCSV');
130 if ($browscap->error or !trim($browscap->data)) {
131 watchdog('browscap', "Couldn't retrieve updated browscap: ".$browscap->error);
132 return;
133 }
134 $browscapfp = fopen($browscapfile, "w");
135 fwrite($browscapfp, $browscap->data);
136 fclose($browscapfp);
137 }
138
139 // Parse the .csv file, importing each row (except the first two)
140 // into the {browscap} table
141 $browscapfp = fopen($browscapfile, 'r');
142 if ($browscapfp) {
143 // Ignore the first two rows (column headers & version info)
144 fgetcsv($browscapfp, 1000); fgetcsv($browscapfp, 1000);
145 while (($browserinfo = fgetcsv($browscapfp, 1000)) != FALSE) {
146 // Strip brackets
147 $useragent = substr($browserinfo[0], 1, -1);
148 // Replace wildcards with SQL equivalents
149 $useragent = strtr($useragent, '*?', '%_');
150 $parent = $browserinfo[1];
151 $browser = $browserinfo[2];
152 $version = $browserinfo[3];
153 $majorversion = $browserinfo[4];
154 $minorversion = $browserinfo[5];
155 $platform = $browserinfo[6];
156 $authenticodeupdate = $browserinfo[7];
157 if ($browserinfo[8] == 'default') {
158 $cssversion = -1;
159 } else {
160 $cssversion = $browserinfo[8];
161 }
162 $frames = _browscap_boolean($browserinfo[9]);
163 $iframes = _browscap_boolean($browserinfo[10]);
164 $htmltables = _browscap_boolean($browserinfo[11]);
165 $cookies = _browscap_boolean($browserinfo[12]);
166 $backgroundsounds = _browscap_boolean($browserinfo[13]);
167 $vbscript = _browscap_boolean($browserinfo[14]);
168 $javascript = _browscap_boolean($browserinfo[15]);
169 $javaapplets = _browscap_boolean($browserinfo[16]);
170 $activexcontrols = _browscap_boolean($browserinfo[17]);
171 $cdf = _browscap_boolean($browserinfo[18]);
172 $aol = _browscap_boolean($browserinfo[19]);
173 $beta = _browscap_boolean($browserinfo[20]);
174 $win16 = _browscap_boolean($browserinfo[21]);
175 $crawler = _browscap_boolean($browserinfo[22]);
176 $stripper = _browscap_boolean($browserinfo[23]);
177 $wap = _browscap_boolean($browserinfo[24]);
178 $netclr = _browscap_boolean($browserinfo[25]);
179
180 db_query('REPLACE {browscap} (useragent,parent,browser,version,'.
181 'majorversion,minorversion,platform,authenticodeupdate,'.
182 'cssversion,frames,iframes,htmltables,cookies,backgroundsounds,'.
183 'vbscript,javascript,javaapplets,activexcontrols,cdf,aol,'.
184 'beta,win16,crawler,stripper,wap,netclr) '.
185 "VALUES('%s','%s','%s','%s','%s','%s','%s','%s',%d,%d,%d,%d,%d,".
186 '%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)',
187 $useragent, $parent, $browser, $version,
188 $majorversion, $minorversion, $platform, $authenticodeupdate,
189 $cssversion, $frames, $iframes, $htmltables, $cookies, $backgroundsounds,
190 $vbscript, $javascript, $javaapplets, $activexcontrols, $cdf, $aol,
191 $beta, $win16, $crawler, $stripper, $wap, $netclr);
192 }
193 fclose($browscapfp);
194 unlink($browscapfile);
195
196 // Phase 2 - for every entry which isn't a top-level entry, plug
197 // in the data from its parent
198 $query = 'SELECT useragent,parent from {browscap} WHERE useragent <> parent';
199 $result = db_query($query);
200 while ($destrow = db_fetch_object($result)) {
201 $query = "SELECT * FROM {browscap} WHERE useragent='%s'";
202 $srcrow = db_fetch_object(db_query($query, $destrow->parent));
203 db_query("UPDATE {browscap} SET browser='%s',version='%s',".
204 "majorversion='%s',minorversion='%s',platform='%s',".
205 "authenticodeupdate='%s',cssversion=%d,frames=%d,iframes=%d,".
206 "htmltables=%d,cookies=%d,backgroundsounds=%d,vbscript=%d,".
207 "javascript=%d,javaapplets=%d,activexcontrols=%d,cdf=%d,".
208 "aol=%d,beta=%d,win16=%d,crawler=%d,stripper=%d,wap=%d,netclr=%d ".
209 "WHERE useragent='%s'",
210 $srcrow->browser,$srcrow->version,
211 $srcrow->majorversion,$srcrow->minorversion,$srcrow->platform,
212 $srcrow->authenticodeupdate,$srcrow->cssversion,$srcrow->frames,$srcrow->iframes,
213 $srcrow->htmltables,$srcrow->cookies,$srcrow->backgroundsounds,$srcrow->vbscript,
214 $srcrow->javascript,$srcrow->javaapplets,$srcrow->activexcontrols,$srcrow->cdf,
215 $srcrow->aol,$srcrow->beta,$srcrow->win16,$srcrow->crawler,$srcrow->stripper,$srcrow->wap,$srcrow->netclr,
216 $destrow->useragent);
217 }
218 // All done updating the browscap info - invalidate cached data
219 // from the last version, and record the version we're currently
220 // using
221 cache_clear_all('browscap:', TRUE);
222 variable_set('browscap_version', $browscapversion);
223 watchdog('browscap', "New version of browscap imported: $browscapversion");
224 }
225 }
226
227 /**
228 * Implementation of hook_exit().
229 *
230 * Keep tabs on browsers that visit
231 */
232 function browscap_exit() {
233 // No point if statistics aren't enabled
234 if (!module_exist('statistics')) {
235 return;
236 }
237
238 // If monitoring is enabled, record the browser
239 if (variable_get('browscap_monitor', FALSE)) {
240 $browser = browscap_get_browser();
241 $browserstring = substr(trim($browser->parent), 0, 255);
242 if ($browserstring == '' or $browserstring == 'Default Browser') {
243 $browserstring = trim($_SERVER['HTTP_USER_AGENT']);
244 }
245 db_query("UPDATE {browscap_statistics} SET counter = counter + 1, is_crawler=%d ".
246 "WHERE parent='%s'", $browser->crawler, $browserstring);
247 // If we affected 0 rows, this is the first time we've seen this browser
248 if (!db_affected_rows()) {
249 // We must create a new row to store counters for the new browser.
250 db_query('INSERT INTO {browscap_statistics} (parent,counter,is_crawler) '.
251 "VALUES('%s', 1, %d)", $browserstring, $browser->crawler);
252 }
253 }
254 }
255
256 /*
257 * Undo a recorded browser visit by request
258 *
259 * This function serves the statistics_filter module, enabling it
260 * to ignore visits from specified roles.
261 */
262 function browscap_unmonitor() {
263 // No point if statistics aren't enabled
264 if (!module_exist('statistics')) {
265 return;
266 }
267
268 // If monitoring is enabled, unrecord the browser
269 if (variable_get('browscap_monitor', FALSE)) {
270 $browser = browscap_get_browser();
271 $browserstring = trim($browser->parent);
272 if ($browserstring == '' or $browserstring == 'Default Browser') {
273 $browserstring = trim($_SERVER['HTTP_USER_AGENT']);
274 }
275 db_query("UPDATE {browscap_statistics} SET counter = counter - 1, is_crawler=%d ".
276 "WHERE parent='%s'", $browser->crawler, $browserstring);
277 }
278 }
279
280 /**
281 * Implementation of hook_perm().
282 *
283 * @return array
284 */
285 function browscap_perm() {
286 return array('administer browscap');
287 }
288
289 /**
290 * Turn monitor on or off
291 *
292 * @return array
293 */
294 function browscap_settings() {
295 // Restrict administration of this module
296 if (user_access('administer browscap') === false) {
297 return drupal_access_denied();
298 }
299
300 $form['browscap_monitor'] = array(
301 '#type' => 'checkbox',
302 '#prefix' => t('<p>Browscap data current as of %fileversion</p>',
303 array('%fileversion' => variable_get('browscap_version', 'Never fetched'))),
304 '#title' => t('Monitor browsers'),
305 '#default_value' => variable_get('browscap_monitor', FALSE),
306 '#description' => t('Monitor all user agents visiting the site.')
307 );
308 return $form;
309 }
310
311 /**
312 * Implementation of hook_menu().
313 *
314 * @return array
315 */
316 function browscap_menu($may_cache) {
317 $items = array();
318
319 if ($may_cache && variable_get('browscap_monitor', FALSE)) {
320 $access = user_access('access statistics');
321
322 $items[] = array('path' => 'admin/logs/useragents',
323 'title' => t('user agents'), 'callback' => 'browscap_top_useragents',
324 'access' => $access, 'weight' => 5);
325 $items[] = array('path' => 'admin/logs/useragents/browsers',
326 'title' => t('browsers'), 'access' => $access);
327 $items[] = array('path' => 'admin/logs/useragents/crawlers',
328 'title' => t('crawlers'), 'access' => $access);
329 }
330
331 return $items;
332 }
333
334 /**
335 * Menu callback; presents the user agents monitoring page.
336 *
337 * @param $view
338 * - "browsers": Only display "real" browsers
339 * - "crawlers": Only display search engine crawlers
340 * - "all": Display all user agents.
341 */
342 function browscap_top_useragents($view = 'all') {
343 if ($view == 'all') {
344 $result = db_query('SELECT SUM(counter) FROM {browscap_statistics}');
345 $total = db_result($result);
346 if (!$total) $total = 1;
347 $query = "SELECT parent,counter,(100*counter)/$total as percent,is_crawler FROM {browscap_statistics}";
348 $query_cnt = 'SELECT COUNT(parent) FROM {browscap_statistics}';
349 $title = t('Top user agents');
350 $header = array(
351 array('data' => t('User agent'), 'field' => 'parent'),
352 array('data' => t('Count'), 'field' => 'counter', 'sort' => 'desc'),
353 array('data' => t('Percent'), 'field' => 'percent'),
354 array('data' => t('Crawler?'), 'field' => 'is_crawler')
355 );
356 }
357 elseif ($view == 'browsers') {
358 $result = db_query('SELECT SUM(counter) FROM {browscap_statistics} WHERE is_crawler=0');
359 $total = db_result($result);
360 if (!$total) $total = 1;
361 $query = "SELECT parent,counter,(100*counter)/$total as percent FROM {browscap_statistics} WHERE is_crawler=0";
362 $query_cnt = 'SELECT COUNT(parent) FROM {browscap_statistics} WHERE is_crawler=0';
363 $title = t('Top browsers');
364 $header = array(
365 array('data' => t('Browser'), 'field' => 'parent'),
366 array('data' => t('Count'), 'field' => 'counter', 'sort' => 'desc'),
367 array('data' => t('Percent'), 'field' => 'percent')
368 );
369 } else {
370 $result = db_query('SELECT SUM(counter) FROM {browscap_statistics} WHERE is_crawler=1');
371 $total = db_result($result);
372 if (!$total) $total = 1;
373 $query = "SELECT parent,counter,(100*counter)/$total as percent FROM {browscap_statistics} WHERE is_crawler=1";
374 $query_cnt = 'SELECT COUNT(parent) FROM {browscap_statistics} WHERE is_crawler=1';
375 $title = t('Top crawlers');
376 $header = array(
377 array('data' => t('Crawler'), 'field' => 'parent'),
378 array('data' => t('Count'), 'field' => 'counter', 'sort' => 'desc'),
379 array('data' => t('Percent'), 'field' => 'percent')
380 );
381 }
382
383 $query .= tablesort_sql($header);
384
385 $result = pager_query($query, 50, 0, $query_cnt);
386
387 while ($useragent = db_fetch_object($result)) {
388 if ($view == 'all') {
389 if ($useragent->is_crawler) {
390 $is_crawler = 'Yes';
391 } else {
392 $is_crawler = 'No';
393 }
394 $rows[] = array($useragent->parent, $useragent->counter, $useragent->percent, $is_crawler);
395 } else {
396 $rows[] = array($useragent->parent, $useragent->counter, $useragent->percent);
397 }
398 }
399 if ($pager = theme('pager', NULL, 50, 0)) {
400 $rows[] = array(array('data' => $pager, 'colspan' => 2));
401 }
402
403 $output .= theme('table', $header, $rows);
404
405 print theme('page', $output, $title);
406 }
407
408 ?>

  ViewVC Help
Powered by ViewVC 1.1.2