gpsd.php.in 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. <?php
  2. # @MASTER@
  3. # Copyright (c) 2006,2010 Chris Kuethe <chris.kuethe@gmail.com>
  4. #
  5. # This file is Copyright (c) 2009-2019 The GPSD project
  6. # SPDX-License-Identifier: BSD-2-clause
  7. # Changed to Google Maps API v3, requires no API key, and shorter code
  8. # Sanjeev Gupta <ghane0@gmail.com> 2013-01-05
  9. global $head, $blurb, $title, $showmap, $autorefresh, $footer, $gmap_key;
  10. global $server, $advertise, $port, $open, $swap_ew, $testmode;
  11. $testmode = 1; # leave this set to 1
  12. # Public script parameters:
  13. # host: host name or address where GPSd runs. Default: from config file
  14. # port: port of GPSd. Default: from config file
  15. # op=view: show just the skyview image instead of the whole HTML page
  16. # sz=small: used with op=view, display a small (240x240px) skyview
  17. # op=json: respond with the GPSd POLL JSON structure
  18. # jsonp=prefix: used with op=json, wrap the POLL JSON in parentheses
  19. # and prepend prefix
  20. # If you're running PHP with the Suhosin patch (like the Debian PHP5 package),
  21. # it may be necessary to increase the value of the
  22. # suhosin.get.max_value_length parameter to 2048. The imgdata parameter used
  23. # for displaying the skyview is longer than the default 512 allowed by Suhosin.
  24. # Debian has the config file at /etc/php5/conf.d/suhosin.ini.
  25. # this script shouldn't take more than a few seconds to run
  26. set_time_limit(3);
  27. ini_set('max_execution_time', 3);
  28. if (!file_exists("gpsd_config.inc"))
  29. write_config();
  30. require_once("gpsd_config.inc");
  31. # sample data
  32. $resp = <<<EOF
  33. {"class":"POLL","time":"2010-04-05T21:27:54.84Z","active":1,
  34. "tpv":[{"class":"TPV","tag":"MID41","device":"/dev/ttyUSB0",
  35. "time":1270517264.240,"ept":0.005,"lat":40.035093060,
  36. "lon":-75.519748733,"alt":31.1,"track":99.4319,
  37. "speed":0.123,"mode":3}],
  38. "sky":[{"class":"SKY","tag":"MID41","device":"/dev/ttyUSB0",
  39. "time":"2010-04-05T21:27:44.84Z","hdop":9.20,"vdop":12.1,
  40. "satellites":[{"PRN":16,"el":55,"az":42,"ss":36,"used":true},
  41. {"PRN":19,"el":25,"az":177,"ss":0,"used":false},
  42. {"PRN":7,"el":13,"az":295,"ss":0,"used":false},
  43. {"PRN":6,"el":56,"az":135,"ss":32,"used":true},
  44. {"PRN":13,"el":47,"az":304,"ss":0,"used":false},
  45. {"PRN":23,"el":66,"az":259,"ss":40,"used":true},
  46. {"PRN":20,"el":7,"az":226,"ss":0,"used":false},
  47. {"PRN":3,"el":52,"az":163,"ss":32,"used":true},
  48. {"PRN":31,"el":16,"az":102,"ss":0,"used":false}
  49. ]
  50. }
  51. ]
  52. }
  53. EOF;
  54. # if we're passing in a query, let's unpack and use it
  55. $op = isset($_GET['op']) ? $_GET['op'] : '';
  56. if (isset($_GET['imgdata']) && $op == 'view'){
  57. $resp = base64_decode($_GET['imgdata']);
  58. if ($resp){
  59. gen_image($resp);
  60. exit(0);
  61. }
  62. } else {
  63. if (isset($_GET['host']))
  64. if (!preg_match('/[^a-zA-Z0-9\.-]/', $_GET['host']))
  65. $server = $_GET['host'];
  66. if (isset($_GET['port']))
  67. if (!preg_match('/\D/', $_GET['port']) && ($port>0) && ($port<65536))
  68. $port = $_GET['port'];
  69. if ($testmode){
  70. $sock = @fsockopen($server, $port, $errno, $errstr, 2);
  71. @fwrite($sock, "?WATCH={\"enable\":true}\n");
  72. usleep(1000);
  73. @fwrite($sock, "?POLL;\n");
  74. usleep(1000);
  75. for($tries = 0; $tries < 10; $tries++){
  76. $resp = @fread($sock, 2000); # SKY can be pretty big
  77. if (preg_match('/{"class":"POLL".+}/i', $resp, $m)){
  78. $resp = $m[0];
  79. break;
  80. }
  81. }
  82. @fclose($sock);
  83. if (!$resp)
  84. $resp = '{"class":"ERROR","message":"no response from GPS daemon"}';
  85. }
  86. }
  87. if ($op == 'view')
  88. gen_image($resp);
  89. else if ($op == 'json')
  90. write_json($resp);
  91. else
  92. write_html($resp);
  93. exit(0);
  94. ###########################################################################
  95. # Function to decide if a PRN is a true GPS bird or SBAS, GBAS, etc.
  96. # Sanjeev Gupta <ghane0@gmail.com> 20150408
  97. # Please refer to gps.h lines ~~ 95 , for a central definition
  98. function isGPS($PRN) {
  99. if ($PRN <= 32) return TRUE ; # Navstar GPS
  100. if ($PRN >= 64 && $PRN <= 96) return TRUE ; # GLONASS
  101. if ($PRN >= 159 ) return TRUE ; # BeiDou ?
  102. return FALSE ; # SBAS, GBAS, unknown
  103. }
  104. function colorsetup($im){
  105. $C['white'] = imageColorAllocate($im, 255, 255, 255);
  106. $C['ltgray'] = imageColorAllocate($im, 191, 191, 191);
  107. $C['mdgray'] = imageColorAllocate($im, 127, 127, 127);
  108. $C['dkgray'] = imageColorAllocate($im, 63, 63, 63);
  109. $C['black'] = imageColorAllocate($im, 0, 0, 0);
  110. $C['red'] = imageColorAllocate($im, 255, 0, 0);
  111. $C['brightgreen'] = imageColorAllocate($im, 0, 255, 0);
  112. $C['darkgreen'] = imageColorAllocate($im, 0, 192, 0);
  113. $C['blue'] = imageColorAllocate($im, 0, 0, 255);
  114. $C['cyan'] = imageColorAllocate($im, 0, 255, 255);
  115. $C['magenta'] = imageColorAllocate($im, 255, 0, 255);
  116. $C['yellow'] = imageColorAllocate($im, 255, 255, 0);
  117. $C['orange'] = imageColorAllocate($im, 255, 128, 0);
  118. return $C;
  119. }
  120. function legend($im, $sz, $C){
  121. $r = 30;
  122. $fn = 5;
  123. $x = $sz - (4*$r+7) - 2;
  124. $y = $sz - $r - 3;
  125. imageFilledRectangle($im, $x, $y, $x + 4*$r + 7, $y + $r +1, $C['dkgray']);
  126. imageRectangle($im, $x+0*$r+1, $y+1, $x + 1*$r + 0, $y + $r, $C['red']);
  127. imageRectangle($im, $x+1*$r+2, $y+1, $x + 2*$r + 2, $y + $r, $C['yellow']);
  128. imageRectangle($im, $x+2*$r+4, $y+1, $x + 3*$r + 4, $y + $r, $C['darkgreen']);
  129. imageRectangle($im, $x+4*$r+6, $y+1, $x + 3*$r + 6, $y + $r, $C['brightgreen']);
  130. imageString($im, $fn, $x+3+0*$r, $y+$r/3, "<30", $C['red']);
  131. imageString($im, $fn, $x+5+1*$r, $y+$r/3, "30+", $C['yellow']);
  132. imageString($im, $fn, $x+7+2*$r, $y+$r/3, "35+", $C['darkgreen']);
  133. imageString($im, $fn, $x+9+3*$r, $y+$r/3, "40+", $C['brightgreen']);
  134. }
  135. function radial($angle, $sz){
  136. #turn into radians
  137. $angle = deg2rad($angle);
  138. # determine length of radius
  139. $r = $sz * 0.5 * 0.95;
  140. # and convert length/azimuth to cartesian
  141. $x0 = sprintf("%d", (($sz * 0.5) - ($r * cos($angle))));
  142. $y0 = sprintf("%d", (($sz * 0.5) - ($r * sin($angle))));
  143. $x1 = sprintf("%d", (($sz * 0.5) + ($r * cos($angle))));
  144. $y1 = sprintf("%d", (($sz * 0.5) + ($r * sin($angle))));
  145. return array($x0, $y0, $x1, $y1);
  146. }
  147. function azel2xy($az, $el, $sz){
  148. global $swap_ew;
  149. #rotate coords... 90deg E = 180deg trig
  150. $az += 270;
  151. #turn into radians
  152. $az = deg2rad($az);
  153. # determine length of radius
  154. $r = $sz * 0.5 * 0.95;
  155. $r -= ($r * ($el/90));
  156. # and convert length/azimuth to cartesian
  157. $x = sprintf("%d", (($sz * 0.5) + ($r * cos($az))));
  158. $y = sprintf("%d", (($sz * 0.5) + ($r * sin($az))));
  159. if ($swap_ew != 0)
  160. $x = $sz - $x;
  161. return array($x, $y);
  162. }
  163. function splot($im, $sz, $C, $e){
  164. if ((0 == $e['PRN']) || (0 == $e['az'] + $e['el']) ||
  165. ($e['az'] < 0) || ($e['el'] < 0))
  166. return;
  167. $color = $C['brightgreen'];
  168. if ($e['ss'] < 40)
  169. $color = $C['darkgreen'];
  170. if ($e['ss'] < 35)
  171. $color = $C['yellow'];
  172. if ($e['ss'] < 30)
  173. $color = $C['red'];
  174. if ($e['el']<10)
  175. $color = $C['blue'];
  176. if ($e['ss'] < 10)
  177. $color = $C['black'];
  178. list($x, $y) = azel2xy($e['az'], $e['el'], $sz);
  179. $r = 12;
  180. if (isset($_GET['sz']) && ($_GET['sz'] == 'small'))
  181. $r = 8;
  182. imageString($im, 3, $x+4, $y+4, $e['PRN'], $C['black']);
  183. if ($e['used'] == true)
  184. if (isGPS($e['PRN']))
  185. imageFilledArc($im, $x, $y, $r, $r, 0, 360, $color, 0);
  186. else
  187. imageFilledDiamond($im, $x, $y, $r, $color);
  188. else
  189. if (isGPS($e['PRN']))
  190. imageArc($im, $x, $y, $r, $r, 0, 360, $color);
  191. else
  192. imageDiamond($im, $x, $y, $r, $color);
  193. }
  194. function imageDiamond($im, $x, $y, $r, $color){
  195. $t = $r/2;
  196. # this lunacy is because imagesetthickness doesn't seem to work
  197. $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t );
  198. imagepolygon($im, $vx, 4, $color);
  199. $t--;
  200. $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t );
  201. imagepolygon($im, $vx, 4, $color);
  202. $t--;
  203. $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t );
  204. imagepolygon($im, $vx, 4, $color);
  205. }
  206. function imageFilledDiamond($im, $x, $y, $r, $color){
  207. $t = $r/2;
  208. while($t){
  209. $vx = array ( $x+$t, $y, $x, $y+$t, $x-$t, $y, $x, $y-$t );
  210. imagepolygon($im, $vx, 4, $color);
  211. $t -= 0.5;
  212. }
  213. }
  214. function elevation($im, $sz, $C, $a){
  215. $b = 90 - $a;
  216. $a = $sz * 0.95 * ($a/180);
  217. imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['ltgray']);
  218. $x = $sz/2 - 16;
  219. $y = $sz/2 - $a;
  220. imageString($im, 2, $x, $y, $b, $C['ltgray']);
  221. }
  222. function skyview($im, $sz, $C){
  223. global $swap_ew;
  224. $a = 90; $a = $sz * 0.95 * ($a/180);
  225. imageFilledArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['mdgray'], 0);
  226. imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['black']);
  227. $x = $sz/2 - 16; $y = $sz/2 - $a;
  228. imageString($im, 2, $x, $y, "0", $C['ltgray']);
  229. $a = 85; $a = $sz * 0.95 * ($a/180);
  230. imageFilledArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['white'], 0);
  231. imageArc($im, $sz/2, $sz/2, $a*2, $a*2, 0, 360, $C['ltgray']);
  232. imageString($im, 1, $sz/2 - 6, $sz+$a, '5', $C['black']);
  233. $x = $sz/2 - 16; $y = $sz/2 - $a;
  234. imageString($im, 2, $x, $y, "5", $C['ltgray']);
  235. for($i = 0; $i < 180; $i += 15){
  236. list($x0, $y0, $x1, $y1) = radial($i, $sz);
  237. imageLine($im, $x0, $y0, $x1, $y1, $C['ltgray']);
  238. }
  239. for($i = 15; $i < 90; $i += 15)
  240. elevation($im, $sz, $C, $i);
  241. $x = $sz/2 - 16; $y = $sz/2 - 8;
  242. /* imageString($im, 2, $x, $y, "90", $C['ltgray']); */
  243. imageString($im, 4, $sz/2 + 4, 2 , 'N', $C['black']);
  244. imageString($im, 4, $sz/2 + 4, $sz - 16 , 'S', $C['black']);
  245. if ($swap_ew != 0){
  246. imageString($im, 4, 4 , $sz/2 + 4, 'E', $C['black']);
  247. imageString($im, 4, $sz - 10 , $sz/2 + 4, 'W', $C['black']);
  248. } else {
  249. imageString($im, 4, 4 , $sz/2 + 4, 'W', $C['black']);
  250. imageString($im, 4, $sz - 10 , $sz/2 + 4, 'E', $C['black']);
  251. }
  252. }
  253. function gen_image($resp){
  254. $sz = 600;
  255. if (isset($_GET['sz']) && ($_GET['sz'] == 'small'))
  256. $sz = 240;
  257. $GPS = json_decode($resp, true);
  258. if ($GPS['class'] != "POLL"){
  259. die("json_decode error: $resp");
  260. }
  261. $im = imageCreate($sz, $sz);
  262. $C = colorsetup($im);
  263. skyview($im, $sz, $C);
  264. if ($sz > 240)
  265. legend($im, $sz, $C);
  266. for($i = 0; $i < count($GPS['sky'][0]['satellites']); $i++){
  267. splot($im, $sz, $C, $GPS['sky'][0]['satellites'][$i]);
  268. }
  269. header("Content-type: image/png");
  270. imagePNG($im);
  271. imageDestroy($im);
  272. }
  273. function dfix($x, $y, $z){
  274. if ($x < 0){
  275. $x = sprintf("%f %s", -1 * $x, $z);
  276. } else {
  277. $x = sprintf("%f %s", $x, $y);
  278. }
  279. return $x;
  280. }
  281. function write_html($resp){
  282. global $sock, $errstr, $errno, $server, $port, $head, $body, $open;
  283. global $blurb, $title, $autorefresh, $showmap, $gmap_key, $footer;
  284. global $testmode, $advertise;
  285. $GPS = json_decode($resp, true);
  286. if ($GPS['class'] != 'POLL'){
  287. die("json_decode error: $resp");
  288. }
  289. header("Content-type: text/html; charset=UTF-8");
  290. global $lat, $lon;
  291. $lat = (float)$GPS['tpv'][0]['lat'];
  292. $lon = (float)$GPS['tpv'][0]['lon'];
  293. $x = $server; $y = $port;
  294. $imgdata = base64_encode($resp);
  295. $server = $x; $port = $y;
  296. if ($autorefresh > 0)
  297. $autorefresh = "<meta http-equiv='Refresh' content='$autorefresh'/>";
  298. else
  299. $autorefresh = '';
  300. $map_head = $map_body = $map_code = '';
  301. if ($showmap == 1) {
  302. $map_head = gen_gmap_head();
  303. $map_body = 'onload="Load()" onunload="GUnload()"';
  304. $map_code = gen_map_code();
  305. } else if ($showmap == 2) {
  306. $map_head = gen_osm_head();
  307. $map_body = 'onload="Load()"';
  308. $map_code = gen_map_code();
  309. }
  310. $part1 = <<<EOF
  311. <?xml version="1.0" encoding="UTF-8"?>
  312. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  313. "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  314. <html xmlns="https://www.w3.org/1999/xhtml">
  315. <head>
  316. {$head}
  317. {$map_head}
  318. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  319. <meta http-equiv="Content-Language" content="en,en-us"/>
  320. <title>{$title} - GPSD Test Station {$lat}, {$lon}</title>
  321. {$autorefresh}
  322. <style>
  323. .warning {
  324. color: #FF0000;
  325. }
  326. .fixed {
  327. font-family: mono-space;
  328. }
  329. .caption {
  330. text-align: left;
  331. margin: 1ex 3em 1ex 3em; /* top right bottom left */
  332. }
  333. .administrivia {
  334. font-size: small;
  335. font-family: verdana, sans-serif;
  336. }
  337. </style>
  338. </head>
  339. <body {$body} {$map_body}>
  340. <center>
  341. <table border="0">
  342. <tr><td align="justify">
  343. {$blurb}
  344. </td>
  345. EOF;
  346. if (!strlen($advertise))
  347. $advertise = $server;
  348. if ($testmode && !$sock)
  349. $part2 = "";
  350. else
  351. $part2 = <<<EOF
  352. <!-- ------------------------------------------------------------ -->
  353. <td rowspan="4" align="center" valign="top">
  354. <img src="?op=view&amp;imgdata={$imgdata}"
  355. width="600" height="600"/>
  356. <br clear="all"/>
  357. <p class="caption">A filled circle means the satellite was used in
  358. the last fix. Green-yellow-red colors indicate signal strength in dB,
  359. green=most and red=least. Diamonds indicate Augmentation satellites.</p>
  360. {$map_code}</td>
  361. </tr>
  362. EOF;
  363. if (!$open)
  364. $part3 = '';
  365. else
  366. $part3 = <<<EOF
  367. <!-- ------------------------------------------------------------ -->
  368. <tr><td align="justify">To get real-time information, connect to
  369. <span class="fixed">telnet://{$advertise}:{$port}/</span> and type "?POLL;"
  370. or "?WATCH={"enable":true,"raw":true}".<br/>
  371. Use a different server:<br/>
  372. <form method=GET action="${_SERVER['SCRIPT_NAME']}">
  373. <input name="host" value="{$advertise}">:
  374. <input name="port" value="{$port}" size="5" maxlength="5">
  375. <input type=submit value="Get Position"><input type=reset></form>
  376. <br/>
  377. </td>
  378. </tr>
  379. EOF;
  380. if ($testmode && !$sock)
  381. $part4 = "<tr><td class='warning'>The gpsd instance that this page monitors is not running.</td></tr>";
  382. else {
  383. $fix = $GPS['tpv'][0];
  384. $sky = $GPS['sky'][0];
  385. $sats = $sky['satellites'];
  386. $fixtype = array('Unknown' => 0, 'No Fix' => 1,'2D Fix' => 2, '3D Fix' => 3);
  387. $type = array_search($fix['mode'],$fixtype);
  388. $nsv = count($sats);
  389. $ts = $fix['time'];
  390. $sat = '';
  391. foreach($sats as $s)
  392. $sat .= sprintf(
  393. "\t<tr><td>%d</td><td>%d</td><td>%d</td><td>%d</td><td>%s</td></tr>\n",
  394. $s['PRN'], $s['el'], $s['az'], $s['ss'], $s['used'] ? 'Y' : 'N'
  395. );
  396. $part4 = <<<EOF
  397. <!-- ------------------------------------------------------------ -->
  398. <tr><td align=center valign=top>
  399. <table border=1>
  400. <tr><th colspan=2 align=center>Current Information</th></tr>
  401. <tr><td>Time (UTC)</td><td>{$ts}</td></tr>
  402. <tr><td>Latitude</td><td>{$fix['lat']}</td></tr>
  403. <tr><td>Longitude</td><td>{$fix['lon']}</td></tr>
  404. <tr><td>Altitude</td><td>{$fix['alt']}</td></tr>
  405. <tr><td>Fix Type</td><td>{$type}</td></tr>
  406. <tr><td>Satellites</td><td>{$nsv}</td></tr>
  407. <tr><td>HDOP</td><td>{$sky['hdop']}</td></tr>
  408. <tr><td>VDOP</td><td>{$sky['vdop']}</td></tr>
  409. </table>
  410. <br/>
  411. <table border=1>
  412. <tr><th colspan=5 align=center>Current Satellites</th></tr>
  413. <tr><th>PRN</th><th>Elevation</th><th>Azimuth</th><th>SS</th><th>Used</th></tr>
  414. $sat </table>
  415. </td></tr>
  416. <!-- raw response:
  417. {$resp}
  418. -->
  419. EOF;
  420. }
  421. $part5 = <<<EOF
  422. </table>
  423. </center>
  424. {$footer}
  425. <hr/>
  426. <p class="administrivia">This script is distributed by the
  427. <a href="@WEBSITE@">GPSD project</a>.</p>
  428. </body>
  429. </html>
  430. EOF;
  431. print $part1 . $part2 . $part3 . $part4 . $part5;
  432. }
  433. function write_json($resp){
  434. header('Content-Type: text/javascript');
  435. if (isset($_GET['jsonp']))
  436. print "{$_GET['jsonp']}({$resp})";
  437. else
  438. print $resp;
  439. }
  440. function write_config(){
  441. $f = fopen("gpsd_config.inc", "a");
  442. if (!$f)
  443. die("can't generate prototype config file. try running this script as root in DOCUMENT_ROOT");
  444. $buf = <<<EOB
  445. <?PHP
  446. \$title = 'My GPS Server';
  447. \$server = 'localhost';
  448. #\$advertise = 'localhost';
  449. \$port = 2947;
  450. \$autorefresh = 0; # number of seconds after which to refresh
  451. \$showmap = 0; # set to 1 if you want to have a google map, set it to 2 if you want a map based on openstreetmap
  452. \$gmap_key = 'GetYourOwnGoogleKey'; # your google API key goes here
  453. \$swap_ew = 0; # set to 1 for upward facing view (nonstandard)
  454. \$open = 0; # set to 1 to show the form to change the GPSd server
  455. ## You can read the header, footer and blurb from a file...
  456. # \$head = file_get_contents('/path/to/header.inc');
  457. # \$body = file_get_contents('/path/to/body.inc');
  458. # \$footer = file_get_contents('/path/to/footer.hinc');
  459. # \$blurb = file_get_contents('/path/to/blurb.inc');
  460. ## ... or you can just define them here
  461. \$head = '';
  462. \$body = '';
  463. \$footer = '';
  464. \$blurb = <<<EOT
  465. This is a
  466. <a href="@WEBSITE@">gpsd</a>
  467. server <blink><font color="red">located someplace</font></blink>.
  468. The hardware is a
  469. <blink><font color="red">hardware description and link</font></blink>.
  470. This machine is maintained by
  471. <a href="mailto:you@example.com">Your Name Goes Here</a>.<br/>
  472. EOT;
  473. ?>
  474. EOB;
  475. fwrite($f, $buf);
  476. fclose($f);
  477. }
  478. function gen_gmap_head() {
  479. global $gmap_key;
  480. return <<<EOT
  481. <script src="//maps.googleapis.com/maps/api/js?sensor=false"/>
  482. <script>
  483. <!--
  484. function Load() {
  485. var map = new google.maps.Map(
  486. document.getElementById('map'), {
  487. center: new google.maps.LatLng({$GLOBALS['lat']}, {$GLOBALS['lon']}),
  488. zoom: 13,
  489. mapTypeId: google.maps.MapTypeId.ROADMAP
  490. });
  491. var marker = new google.maps.Marker({
  492. position: new google.maps.LatLng({$GLOBALS['lat']}, {$GLOBALS['lon']}),
  493. map: map
  494. });
  495. }
  496. google.maps.event.addDomListener(window, 'load', initialize);
  497. -->
  498. </script>
  499. EOT;
  500. }
  501. function gen_osm_head() {
  502. global $GPS;
  503. return <<<EOT
  504. <script src="http://openlayers.org/api/OpenLayers.js" />
  505. <script>
  506. <!--
  507. function Load() {
  508. document.getElementById("map").firstChild.data = "";
  509. var map = new OpenLayers.Map("map", {
  510. controls: [
  511. new OpenLayers.Control.Navigation(),
  512. new OpenLayers.Control.PanZoomBar(),
  513. new OpenLayers.Control.ScaleLine(),
  514. new OpenLayers.Control.LayerSwitcher()
  515. ]
  516. });
  517. var layer = new OpenLayers.Layer.OSM("Open Street Map");
  518. map.addLayer(layer);
  519. var center = new OpenLayers.LonLat({$GLOBALS['lon']}, {$GLOBALS['lat']})
  520. .transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
  521. map.setCenter(center, 12);
  522. var markers = new OpenLayers.Layer.Markers("Markers");
  523. markers.addMarker(new OpenLayers.Marker(center));
  524. map.addLayer(markers);
  525. }
  526. -->
  527. </script>
  528. EOT;
  529. }
  530. function gen_map_code() {
  531. return <<<EOT
  532. <br/>
  533. <div id="map" style="width: 550px; height: 400px; border:1px; border-style: solid;">
  534. Loading...
  535. <noscript>
  536. <span class='warning'>Sorry: you must enable javascript to view our maps.</span><br/>
  537. </noscript>
  538. </div>
  539. EOT;
  540. }
  541. ?>