summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfabiszewski <github@ushuaia.pl>2013-06-19 13:27:14 +0200
committerbfabiszewski <github@ushuaia.pl>2013-06-19 13:27:14 +0200
commit2c15d1d2344fe32f549f755de24b973822631181 (patch)
tree5a5051b36c140d54b51039a85721fe73aac46944
parenteeabf5e5a5070084472c2af62b60820595d686f1 (diff)
downloadRunnerUpLive-2c15d1d2344fe32f549f755de24b973822631181.zip
phpTrackme 1.0
-rw-r--r--LICENSE339
-rwxr-xr-xREADME32
-rwxr-xr-xauth.php117
-rwxr-xr-xconfig.php51
-rwxr-xr-xdownload.php221
-rwxr-xr-xexport.php26
-rwxr-xr-xgetpositions.php87
-rwxr-xr-xgettrips.php52
-rwxr-xr-xindex.php186
-rwxr-xr-xlang.php82
-rwxr-xr-xlogout.php30
-rwxr-xr-xmain.css152
-rwxr-xr-xmain.js412
-rwxr-xr-xrequests.php268
-rwxr-xr-xtrackme.sql128
15 files changed, 2183 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/README b/README
new file mode 100755
index 0000000..fb83fd3
--- /dev/null
+++ b/README
@@ -0,0 +1,32 @@
+This is a simple web viewer for GPS tracks uploaded with mobile client.
+It is designed to work with Android version of great app TrackMe (http://www.luisespinosa.com/trackme_eng.html),
+but it should be easy to adjust it for other clients.
+Interface "look and feel" is based on TrackMe Display (http://forum.xda-developers.com/showthread.php?t=477394).
+It currently uses Google Maps API, but work on OpenStreetMap is in progress.
+
+Live demo:
+- http://flaa.fabiszewski.net/phptrackme/
+
+Requirements:
+- php 5
+- mysql
+- browser with javascript enabled, cookies for authentication
+
+Features:
+- simple
+- allows live tracking
+- track statistics
+- altitudes graph
+- multiple users
+- user authentication
+- Google Maps API v3
+- ajax
+- server based configuration
+
+Todo
+- OpenStreetMap API
+- client based configuration
+- write opensource client?
+
+License
+- GPL
diff --git a/auth.php b/auth.php
new file mode 100755
index 0000000..ab4729c
--- /dev/null
+++ b/auth.php
@@ -0,0 +1,117 @@
+<?php
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+require_once("config.php");
+require_once("lang.php");
+$mysqli = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
+if ($mysqli->connect_errno) {
+ printf("Connect failed: %s\n", $mysqli->connect_error);
+ exit();
+}
+$auth = NULL;
+if ($require_authentication) {
+ /* authentication */
+ session_name('trackme');
+ session_start();
+ $sid = session_id();
+
+ $auth = (isset($_SESSION['auth']) ? $_SESSION['auth'] : "");
+ $user = (isset($_REQUEST['user']) ? $_REQUEST['user'] : "");
+ $pass = (isset($_REQUEST['pass']) ? md5($salt.$_REQUEST['pass']) : "");
+ @$ssl = ($_SERVER['HTTPS'] == "" ? "http" : "https");
+ $auth_error = (isset($_REQUEST['auth_error']) ? $_REQUEST['auth_error'] : 0);
+
+ // not authenticated and username not submited
+ // load form
+ if ((!$auth) && (!$user)){
+ print
+ '<!DOCTYPE html>
+ <html>
+ <head>
+ <title>'.$lang_title.'</title>
+ <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
+ <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
+ <link rel="stylesheet" type="text/css" href="main.css">
+ <script type="text/javascript">
+ function focus() {
+ document.forms[0].elements[0].focus();
+ }
+ </script>
+ </head>
+ <body onload="focus()">
+ <div id="login">
+ <div id="title">'.$lang_title.'</div>
+ <div id="subtitle">'.$lang_private.'</div>
+ <form action="index.php" method="post">
+ '.$lang_username.':<br />
+ <input type="text" name="user"><br />
+ '.$lang_password.':<br />
+ <input type="password" name="pass"><br />
+ <br />
+ <input type="submit" value="'.$lang_login.'">
+ </form>
+ <div id="error">'.(($auth_error==1) ? $lang_authfail : "").'</div>
+ </div>
+
+ </body>
+ </html>';
+ $mysqli->close();
+ exit;
+ }
+
+ // username submited
+ if ((!$auth) && ($user)){
+ $query = $mysqli->prepare("SELECT ID,username,password FROM users WHERE username=? LIMIT 1");
+ $query->bind_param('s', $user);
+ $query->execute();
+ $query->bind_result($rec_ID, $rec_user, $rec_pass);
+ $query->fetch();
+ $query->free_result();
+ //correct pass
+ if (($user==$rec_user) && ($pass==$rec_pass)) {
+ // login successful
+ //delete old session
+ $_SESSION = NULL;
+ session_destroy();
+ // start new session
+ session_name('trackme');
+ session_start();
+ $_SESSION['auth'] = $rec_ID;
+
+ $url = str_replace("//", "/", $_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME'])."/index.php");
+ header("Location: $ssl://$url");
+ exit;
+ } else {
+ // unsuccessful
+ $error = "?auth_error=1";
+ // destroy session
+ $_SESSION = NULL;
+ if (isset($_COOKIE[session_name('trackme')])) {
+ setcookie(session_name('trackme'),'',time()-42000,'/');
+ }
+ session_destroy();
+ $mysqli->close();
+ $url = str_replace("//", "/", $_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME'])."/index.php");
+ header("Location: $ssl://$url$error");
+ exit;
+ }
+ }
+ /* end of authentication */
+}
+?>
diff --git a/config.php b/config.php
new file mode 100755
index 0000000..344efd6
--- /dev/null
+++ b/config.php
@@ -0,0 +1,51 @@
+<?php
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+$version = "1.0";
+// map drawing framework
+// (gmaps = google maps, osm = openstreetmap (not supported yet))
+$mapapi = "gmaps";
+// you may add your google maps api key
+// this is not obligatory by now
+//$gkey =
+
+// db
+$dbhost = ""; // mysql host, eg. localhost
+$dbuser = ""; // database user
+$dbpass = ""; // database pass
+$dbname = ""; // database name
+$salt = ""; // fill in random string here, it will increase security of password hashes
+
+// other
+// require login/password authentication
+// (0 = no, 1 = yes)
+$require_authentication = 0;
+// allow automatic registration of new users
+// (0 = no, 1 = yes)
+$allow_registration = 0;
+// Default interval in seconds for live auto reload
+$interval = 10;
+// Default language
+// (en, pl)
+$lang = "en";
+// units
+// (metric, imperial)
+$units = "metric";
+
+?>
diff --git a/download.php b/download.php
new file mode 100755
index 0000000..995f190
--- /dev/null
+++ b/download.php
@@ -0,0 +1,221 @@
+<?php
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+require_once("auth.php");
+$type = (isset($_REQUEST["type"]) ? $_REQUEST["type"] : "kml");
+$userid = ((isset($_REQUEST["userid"]) && is_numeric($_REQUEST["userid"])) ? $_REQUEST["userid"] : 0);
+$trackid = ((isset($_REQUEST["trackid"]) && is_numeric($_REQUEST["trackid"])) ? $_REQUEST["trackid"] : 0);
+
+if ($units=="imperial") {
+ $factor_kmh = 0.62; //to mph
+ $unit_kmh = "mph";
+ $factor_m = 3.28; // to feet
+ $unit_m = "ft";
+ $factor_km = 0.62; // to miles
+ $unit_km = "mi";
+}
+else {
+ $factor_kmh = 1;
+ $unit_kmh = "km/h";
+ $factor_m = 1;
+ $unit_m = "m";
+ $factor_km = 1;
+ $unit_km = "km";
+}
+
+function haversine_distance($lat1, $lon1, $lat2, $lon2) {
+ $lat1 = deg2rad($lat1);
+ $lon1 = deg2rad($lon1);
+ $lat2 = deg2rad($lat2);
+ $lon2 = deg2rad($lon2);
+ $latD = $lat2 - $lat1;
+ $lonD = $lon2 - $lon1;
+ $angle = 2*asin(sqrt(pow(sin($latD/2),2)+cos($lat1)*cos($lat2)*pow(sin($lonD/2),2)));
+ return $angle * 6371000;
+}
+function addStyle($xml,$name,$url) {
+ $xml->startElement("Style");
+ $xml->writeAttribute("id", $name."Style");
+ $xml->startElement("IconStyle");
+ $xml->writeAttribute("id", $name."Icon");
+ $xml->startElement("Icon");
+ $xml->writeElement("href", $url);
+ $xml->endElement();
+ $xml->endElement();
+ $xml->endElement();
+}
+function toHMS($s) {
+ $d = floor($s/86400);
+ $h = floor(($s%86400)/3600);
+ $m = floor((($s%86400)%3600)/60);
+ $s = (($s%86400)%3600)%60;
+ return (($d>0)?($d." d "):"").(substr("00".$h,-2)).":".(substr("00".$m,-2)).":".(substr("00".$s,-2));
+}
+
+if ($trackid>0 && $userid>0) {
+ $query = $mysqli->prepare("SELECT positions.ID,Latitude,Longitude,Altitude,Speed,Angle,DateOccurred,username,Name FROM positions LEFT JOIN users ON (positions.FK_Users_ID=users.ID) LEFT JOIN trips ON (positions.FK_Trips_ID=trips.ID) WHERE positions.FK_Users_ID=? AND positions.FK_Trips_ID=? ORDER BY positions.DateOccurred");
+ $query->bind_param("ii", $userid, $trackid);
+ $query->execute();
+ $query->store_result();
+ $query->bind_result($positionid,$latitude,$longitude,$altitude,$speed,$angle,$dateoccured,$username,$trackname);
+ $query->fetch(); // take just one row to get trackname etc
+ $query->data_seek(0); // and reset result set
+ switch ($type) {
+ case "kml":
+ default:
+ header("Content-type: application/vnd.google-earth.kml+xml");
+ header("Content-Disposition: attachment; filename=\"track$trackid.kml\"");
+ $xml = new XMLWriter();
+ $xml->openURI("php://output");
+ $xml->startDocument("1.0");
+ $xml->startElement("kml");
+ $xml->writeAttribute("xmlns", "http://earth.google.com/kml/2.1");
+ $xml->setIndent(true);
+ $xml->startElement("Document");
+ $xml->writeElement("name", $trackname);
+ // line style
+ $xml->startElement("Style");
+ $xml->writeAttribute("id", "lineStyle");
+ $xml->startElement("LineStyle");
+ $xml->writeElement("color","7f0000ff");
+ $xml->writeElement("width","4");
+ $xml->endElement();
+ $xml->endElement();
+ // marker styles
+ addStyle($xml,"red","http://maps.google.com/mapfiles/markerA.png");
+ addStyle($xml,"green","http://maps.google.com/mapfiles/marker_greenB.png");
+ addStyle($xml,"gray","http://labs.google.com/ridefinder/images/mm_20_gray.png");
+ $style = "#redStyle"; // for first element
+ $i = 0;
+ $totalMeters = 0;
+ $totalSeconds = 0;
+ while ($query->fetch()) {
+ $distance = (isset($prev_latitude))?haversine_distance($prev_latitude,$prev_longitude,$latitude,$longitude):0;
+ $prev_latitude = $latitude;
+ $prev_longitude = $longitude;
+ $seconds = (isset($prev_dateoccured))?(strtotime($dateoccured)-strtotime($prev_dateoccured)):0;
+ $prev_dateoccured = $dateoccured;
+ $totalMeters += $distance;
+ $totalSeconds += $seconds;
+
+ if(++$i == $query->num_rows) { $style = "#greenStyle"; } // last element
+ $xml->startElement("Placemark");
+ $xml->writeAttribute("id", $positionid);
+ //$xml->writeElement("name", $i);
+ $description =
+ "<div style=\"font-weight: bolder;padding-bottom: 10px;border-bottom: 1px solid gray;\">".$lang_user.": ".strtoupper($username)."<br />".$lang_track.": ".strtoupper($trackname).
+ "</div>".
+ "<div>".
+ "<div style=\"padding-top: 10px;\"><b>".$lang_time.":</b> ".$dateoccured."<br />".
+ (($speed)?"<b>".$lang_speed.":</b> ".round($speed*3.6,2*$factor_kmh)." ".$unit_kmh."<br />":"").
+ (($altitude != null)?"<b>".$lang_altitude.":</b> ".round($altitude*$factor_m)." ".$unit_m."<br />":"").
+ "<b>".$lang_ttime.":</b> ".toHMS($totalSeconds)."<br />".
+ "<b>".$lang_aspeed.":</b> ".(($totalSeconds!=0)?round($totalMeters/$totalSeconds*3.6*$factor_kmh,2):0)." ".$unit_kmh."<br />".
+ "<b>".$lang_tdistance.":</b> ".round($totalMeters/1000*$factor_km,2)." ".$unit_km."<br />"."</div>".
+ "<div style=\"font-size: smaller;padding-top: 10px;\">".$lang_point." ".$i." ".$lang_of." ".($query->num_rows-1)."</div>".
+ "</div>";
+ $xml->startElement("description");
+ $xml->writeCData($description);
+ $xml->endElement();
+ $xml->writeElement("styleUrl", $style);
+ $xml->startElement("Point");
+ $coordinate[$i] = $longitude.",".$latitude.(($altitude) ? ",".$altitude : "");
+ $xml->writeElement("coordinates", $coordinate[$i]);
+ $xml->endElement();
+ $xml->endElement();
+ $style = "#grayStyle"; // other elements
+ }
+ $coordinates = implode("\n",$coordinate);
+ $xml->startElement("Placemark");
+ $xml->writeElement("styleUrl", "#lineStyle");
+ $xml->startElement("LineString");
+ $xml->writeElement("coordinates", $coordinates);
+ $xml->endElement();
+ $xml->endElement();
+
+
+ $xml->endElement();
+ $xml->endElement();
+ $xml->endDocument();
+ $xml->flush();
+
+ break;
+
+ case "gpx":
+ header("Content-type: application/application/gpx+xm");
+ header("Content-Disposition: attachment; filename=\"track$trackid.gpx\"");
+ $xml = new XMLWriter();
+ $xml->openURI("php://output");
+ $xml->startDocument("1.0");
+ $xml->startElement("gpx");
+ $xml->writeAttribute("xmlns", "http://www.topografix.com/GPX/1/1");
+ $xml->writeAttribute("xmlns:gpxdata", "http://www.cluetrust.com/XML/GPXDATA/1/0");
+ $xml->writeAttribute("creator", "phpTrackme");
+ $xml->writeAttribute("version", "1.1");
+ $xml->startElement("metadata");
+ $xml->writeElement("name", $trackname);
+ $xml->writeElement("time", str_replace(" ","T",$dateoccured));
+ $xml->endElement();
+ $xml->startElement("trk");
+ $xml->writeElement("name", $trackname);
+ $xml->startElement("trkseg");
+ $i = 0;
+ $totalMeters = 0;
+ $totalSeconds = 0;
+ while ($query->fetch()) {
+ $distance = (isset($prev_latitude))?haversine_distance($prev_latitude,$prev_longitude,$latitude,$longitude):0;
+ $prev_latitude = $latitude;
+ $prev_longitude = $longitude;
+ $seconds = (isset($prev_dateoccured))?(strtotime($dateoccured)-strtotime($prev_dateoccured)):0;
+ $prev_dateoccured = $dateoccured;
+ $totalMeters += $distance;
+ $totalSeconds += $seconds;
+ $xml->startElement("trkpt");
+ $xml->writeAttribute("lat", $latitude);
+ $xml->writeAttribute("lon", $longitude);
+ if($altitude) { $xml->writeElement("ele", $altitude); }
+ $xml->writeElement("time", str_replace(" ","T",$dateoccured));
+ $xml->writeElement("name", ++$i);
+ $xml->startElement("desc");
+ $description =
+ $lang_user.": ".strtoupper($username)." ".$lang_track.": ".strtoupper($trackname).
+ " ".$lang_time.": ".$dateoccured.
+ (($speed)?" ".$lang_speed.": ".round($speed*3.6,2*$factor_kmh)." ".$unit_kmh:"").
+ (($altitude != null)?" ".$lang_altitude.": ".round($altitude*$factor_m)." ".$unit_m:"").
+ " ".$lang_ttime.": ".toHMS($totalSeconds)."".
+ " ".$lang_aspeed.": ".(($totalSeconds!=0)?round($totalMeters/$totalSeconds*3.6*$factor_kmh,2):0)." ".$unit_kmh.
+ " ".$lang_tdistance.": ".round($totalMeters/1000*$factor_km,2)." ".$unit_km.
+ " ".$lang_point." ".$i." ".$lang_of." ".($query->num_rows-1);
+ $xml->writeCData($description);
+ $xml->endElement();
+ $xml->endElement();
+ }
+ $xml->endElement();
+ $xml->endElement();
+ $xml->endElement();
+ $xml->endDocument();
+ $xml->flush();
+
+ break;
+ }
+ $query->free_result();
+ $query->close();
+}
+$mysqli->close();
+?>
diff --git a/export.php b/export.php
new file mode 100755
index 0000000..7df3960
--- /dev/null
+++ b/export.php
@@ -0,0 +1,26 @@
+<?php
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+// FIXME
+// Do we really need this?
+// It is easier to export from web interface.
+// If needed it may be easily adjusted from download.php
+echo "<Result>0</Result>";
+exit();
+?>
diff --git a/getpositions.php b/getpositions.php
new file mode 100755
index 0000000..2f22aa0
--- /dev/null
+++ b/getpositions.php
@@ -0,0 +1,87 @@
+<?php
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+require_once("auth.php");
+
+$userid = ((isset($_REQUEST["userid"]) && is_numeric($_REQUEST["userid"])) ? $_REQUEST["userid"] : 0);
+$trackid = ((isset($_REQUEST["trackid"]) && is_numeric($_REQUEST["trackid"])) ? $_REQUEST["trackid"] : 0);
+
+function haversine_distance($lat1, $lon1, $lat2, $lon2) {
+ $lat1 = deg2rad($lat1);
+ $lon1 = deg2rad($lon1);
+ $lat2 = deg2rad($lat2);
+ $lon2 = deg2rad($lon2);
+ $latD = $lat2 - $lat1;
+ $lonD = $lon2 - $lon1;
+ $angle = 2*asin(sqrt(pow(sin($latD/2),2)+cos($lat1)*cos($lat2)*pow(sin($lonD/2),2)));
+ return $angle * 6371000;
+}
+
+if ($userid) {
+ if ($trackid) {
+ // get all track data
+ $query = $mysqli->prepare("SELECT positions.ID,Latitude,Longitude,Altitude,Speed,Angle,DateOccurred,username,trips.Name,trips.ID FROM positions LEFT JOIN users ON (positions.FK_Users_ID=users.ID) LEFT JOIN trips ON (positions.FK_Trips_ID=trips.ID) WHERE positions.FK_Users_ID=? AND positions.FK_Trips_ID=? ORDER BY positions.DateOccurred");
+ $query->bind_param('ii', $userid, $trackid);
+ }
+ else {
+ // get data only for latest point
+ $query = $mysqli->prepare("SELECT positions.ID,Latitude,Longitude,Altitude,Speed,Angle,DateOccurred,username,trips.Name,trips.ID FROM positions LEFT JOIN users ON (positions.FK_Users_ID=users.ID) LEFT JOIN trips ON (positions.FK_Trips_ID=trips.ID) WHERE positions.FK_Users_ID=? ORDER BY positions.DateOccurred DESC LIMIT 1");
+ $query->bind_param('i', $userid);
+ }
+ $query->execute();
+ $query->bind_result($positionid,$latitude,$longitude,$altitude,$speed,$angle,$dateoccured,$username,$trackname,$trackid);
+
+ header("Content-type: text/xml");
+ $xml = new XMLWriter();
+ $xml->openURI("php://output");
+ $xml->startDocument("1.0");
+ $xml->setIndent(true);
+ $xml->startElement('root');
+
+ while ($query->fetch()) {
+ $xml->startElement("position");
+ $xml->writeAttribute("id", $positionid);
+ $xml->writeElement("latitude", $latitude);
+ $xml->writeElement("longitude", $longitude);
+ $xml->writeElement("altitude", ($altitude)?round($altitude):$altitude);
+ $xml->writeElement("speed", $speed);
+ $xml->writeElement("angle", $angle);
+ $xml->writeElement("dateoccured", $dateoccured);
+ $xml->writeElement("username", $username);
+ $xml->writeElement("trackid", $trackid);
+ $xml->writeElement("trackname", $trackname);
+ $distance = (isset($prev_latitude))?haversine_distance($prev_latitude,$prev_longitude,$latitude,$longitude):0;
+ $prev_latitude = $latitude;
+ $prev_longitude = $longitude;
+ $xml->writeElement("distance", round($distance));
+ $seconds = (isset($prev_dateoccured))?(strtotime($dateoccured)-strtotime($prev_dateoccured)):0;
+ $prev_dateoccured = $dateoccured;
+ $xml->writeElement("seconds", $seconds);
+ $xml->endElement();
+ }
+
+ $xml->endElement();
+ $xml->endDocument();
+ $xml->flush();
+
+ $query->free_result();
+}
+
+$mysqli->close();
+?>
diff --git a/gettrips.php b/gettrips.php
new file mode 100755
index 0000000..6883d08
--- /dev/null
+++ b/gettrips.php
@@ -0,0 +1,52 @@
+<?php
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+require_once("auth.php");
+
+$userid = ((isset($_REQUEST["userid"]) && is_numeric($_REQUEST["userid"])) ? $_REQUEST["userid"] : 0);
+
+if ($userid) {
+ $query = $mysqli->prepare("SELECT ID,Name FROM trips WHERE FK_Users_ID=? ORDER BY ID DESC");
+ $query->bind_param('i', $userid);
+ $query->execute();
+ $query->bind_result($trackid,$trackname);
+
+ header("Content-type: text/xml");
+ $xml = new XMLWriter();
+ $xml->openURI("php://output");
+ $xml->startDocument("1.0");
+ $xml->setIndent(true);
+ $xml->startElement('root');
+
+ while ($query->fetch()) {
+ $xml->startElement("trip");
+ $xml->writeElement("trackid", $trackid);
+ $xml->writeElement("trackname", $trackname);
+ $xml->endElement();
+ }
+
+ $xml->endElement();
+ $xml->endDocument();
+ $xml->flush();
+
+ $query->free_result();
+}
+
+$mysqli->close();
+?>
diff --git a/index.php b/index.php
new file mode 100755
index 0000000..c50a06d
--- /dev/null
+++ b/index.php
@@ -0,0 +1,186 @@
+<?php
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+require_once("auth.php");
+
+if ($auth) {
+ // get username
+ $query = "SELECT username FROM users WHERE ID='$auth' LIMIT 1";
+ $result = $mysqli->query($query);
+ $row = $result->fetch_assoc();
+ $user = $row["username"];
+
+ // users
+ $user_form = '<u>'.$lang_user.'</u><br />'.$user.' (<a href="logout.php">'.$lang_logout.'</a>)';
+}
+else {
+ // free access
+ // prepare user select form
+ $user_form = '
+ <u>'.$lang_user.'</u><br />
+ <form>
+ <select name="user" onchange="selectUser(this)">
+ <option value=\"0\">'.$lang_suser.'</option>';
+ $query = "SELECT ID,username FROM users ORDER BY username";
+ $result = $mysqli->query($query);
+ while ($row = $result->fetch_assoc()) {
+ $user_form .= sprintf("<option value=\"%s\">%s</option>\n", $row["ID"], $row["username"]);
+ }
+$user_form .= '
+</select>
+</form>
+';
+}
+
+
+// prepare track select form
+$track_form = '
+<u>'.$lang_track.'</u><br />
+<form>
+<select name="track" onchange="selectTrack(this)">';
+$query = "SELECT * FROM trips WHERE FK_Users_ID='$auth' ORDER BY ID DESC";
+$result = $mysqli->query($query);
+$trackid = "";
+while ($row = $result->fetch_assoc()) {
+ if ($trackid == "") { $trackid = $row["ID"]; } // get first row
+ $track_form .= sprintf("<option value=\"%s\">%s</option>\n", $row["ID"], $row["Name"]);
+}
+$track_form .= '
+</select>
+<input id="latest" type="checkbox" onchange="toggleLatest();"> '.$lang_latest.'<br />
+</form>
+';
+
+print
+'<!DOCTYPE html>
+<html>
+ <head>
+ <title>'.$lang_title.'</title>
+ <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
+ <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
+ <link rel="stylesheet" type="text/css" href="main.css">
+ <script>
+ var interval = '.$interval.';
+ var userid = '.(($auth)?$auth:-1).';
+ var trackid = '.(($trackid)?$trackid:-1).';
+ var lang_user = "'.$lang_user.'";
+ var lang_time = "'.$lang_time.'";
+ var lang_speed = "'.$lang_speed.'";
+ var lang_altitude = "'.$lang_altitude.'";
+ var lang_ttime = "'.$lang_ttime.'";
+ var lang_aspeed = "'.$lang_aspeed.'";
+ var lang_tdistance = "'.$lang_tdistance.'";
+ var lang_point = "'.$lang_point.'";
+ var lang_of = "'.$lang_of.'";
+ var lang_summary = "'.$lang_summary.'";
+ var lang_latest = "'.$lang_latest.'";
+ var lang_track = "'.$lang_track.'";
+ var lang_newinterval = "'.$lang_newinterval.'";
+ var units = "'.$units.'";
+ </script>
+ <script type="text/javascript" src="main.js">
+ </script>
+';
+if ($mapapi == "gmaps") {
+ print
+' <script type="text/javascript"
+ src="https://maps.googleapis.com/maps/api/js?'.(isset($gkey)?'key='.$gkey.'&':'').'sensor=false">
+ </script>
+ <script type="text/javascript">
+ var map;
+ var polies = new Array();
+ var markers = new Array();
+ var popups = new Array();
+ google.maps.visualRefresh = true;
+ var polyOptions = {
+ strokeColor: \'#FF0000\',
+ strokeOpacity: 1.0,
+ strokeWeight: 2
+ }
+ var mapOptions = {
+ center: new google.maps.LatLng(52.23, 21.01),
+ zoom: 8,
+ mapTypeId: google.maps.MapTypeId.ROADMAP,
+ scaleControl: true
+ };
+ function init() {
+ map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
+ }
+ </script>
+';
+}
+else {
+ print
+' <script type="text/javascript"
+ src="http://openlayers.org/api/OpenLayers.js">
+ </script>
+ <script>
+ function init() {
+ map = new OpenLayers.Map("map-canvas");
+ map.addLayer(new OpenLayers.Layer.OSM());
+ var fromProjection = new OpenLayers.Projection("EPSG:4326"); // Transform from WGS 1984
+ var toProjection = new OpenLayers.Projection("EPSG:900913"); // to Spherical Mercator Projection
+ var position = new OpenLayers.LonLat(21.01,52.23).transform(fromProjection, toProjection);
+ var zoom = 8;
+ map.setCenter(position, zoom);
+ }
+ </script>
+';
+}
+print '
+ <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+ <script type="text/javascript">
+ google.load("visualization", "1", {packages:["corechart"]});
+ </script>
+
+ </head>
+ <body onload="init();loadTrack(userid,trackid,1);">
+ <div id="menu">
+ <div id="menu-content">
+ <div id="user">
+ '.$user_form.'
+ </div>
+ <div id="trip">
+ '.$track_form.'
+ <input id="latest" type="checkbox" onchange="autoReload();"> '.$lang_autoreload.' (<a href="javascript:void(0);" onclick="setTime()"><span id="auto">'.$interval.'</span></a> s)<br />
+ <a href="javascript:void(0);" onclick="loadTrack(userid,trackid,0)">'.$lang_reload.'</a><br />
+ </div>
+ <div id="summary"></div>
+ <div id="other">
+ <a href="javascript:void(0);" onclick="toggleChart();">'.$lang_chart.'</a><br />
+ </div>
+ <div id="export">
+ <u>'.$lang_download.'</u><br />
+ <a href="javascript:void(0);" onclick="load(\'kml\',userid,trackid)">kml</a><br />
+ <a href="javascript:void(0);" onclick="load(\'gpx\',userid,trackid)">gpx</a><br />
+ </div>
+ </div>
+ <div id="footer">phpTrackme '.$version.'</div>
+ </div>
+ <div id="main">
+ <div id="map-canvas"></div>
+ <div id="bottom">
+ <div id="chart"></div>
+ <div id="close"><a href="javascript:void(0);" onclick="toggleChart(0);">'.$lang_close.'</a></div>
+ </div>
+ </div>
+ </body>
+</html>';
+$mysqli->close();
+?>
diff --git a/lang.php b/lang.php
new file mode 100755
index 0000000..bd508c9
--- /dev/null
+++ b/lang.php
@@ -0,0 +1,82 @@
+<?php
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+switch($lang) {
+ default:
+ case "en":
+ $lang_title = "fabiszewski.net • geolocation";
+ $lang_private = "You need login and password to access this page.";
+ $lang_authfail = "Wrong username or password";
+ $lang_user = "User";
+ $lang_track = "Track";
+ $lang_latest = "latest position";
+ $lang_autoreload = "autoreload";
+ $lang_reload = "Reload now";
+ $lang_download = "Download data";
+ $lang_chart = "Altitudes chart";
+ $lang_close = "close";
+ $lang_time = "Time";
+ $lang_speed = "Speed";
+ $lang_altitude = "Altitude";
+ $lang_ttime = "Total time";
+ $lang_aspeed = "Average speed";
+ $lang_tdistance = "Total dist.";
+ $lang_point = "Point"; //Point x of y
+ $lang_of = "of";
+ $lang_summary = "Trip summary";
+ $lang_suser = "select user";
+ $lang_logout = "log out";
+ $lang_login = "Log in";
+ $lang_username = "Username";
+ $lang_password = "Password";
+ $lang_language = "Language";
+ $lang_newinterval = "Enter new interval value (seconds)";
+ break;
+
+ case "pl":
+ $lang_title = "fabiszewski.net &bullet; geolocation";
+ $lang_private = "Aby się zalogować musisz podać login i hasło";
+ $lang_authfail = "błędny login lub hasło";
+ $lang_user = "Użytkownik";
+ $lang_track = "Trasa";
+ $lang_latest = "ostatnia pozycja";
+ $lang_autoreload = "odświeżaj";
+ $lang_reload = "Odśwież teraz";
+ $lang_download = "Pobierz dane";
+ $lang_chart = "Wykres przewyższeń";
+ $lang_close = "zamknij";
+ $lang_time = "Czas";
+ $lang_speed = "Prędkość";
+ $lang_altitude = "Wysokość";
+ $lang_ttime = "Czas podróży";
+ $lang_aspeed = "Średnia prędkość";
+ $lang_tdistance = "Odległość";
+ $lang_suser = "wybierz login";
+ $lang_point = "Punkt";
+ $lang_of = "z";
+ $lang_summary = "Podsumowanie";
+ $lang_logout = "wyloguj";
+ $lang_login = "zaloguj";
+ $lang_username = "Login";
+ $lang_password = "Hasło";
+ $lang_language = "Język";
+ $lang_newinterval = "Podaj częstotliwość odświeżania (w sekundach)";
+ break;
+}
+?>
diff --git a/logout.php b/logout.php
new file mode 100755
index 0000000..7a9f6c2
--- /dev/null
+++ b/logout.php
@@ -0,0 +1,30 @@
+<?php
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+session_name('trackme');
+session_start();
+$_SESSION = NULL;
+if (isset($_COOKIE[session_name('trackme')])) {
+ setcookie(session_name('trackme'),'',time()-42000,'/');
+}
+session_destroy();
+@$ssl = ($_SERVER['HTTPS'] == "" ? "http" : "https");
+$url = str_replace("//", "/", $_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME'])."/index.php");
+header("Location: $ssl://$url");
+?>
diff --git a/main.css b/main.css
new file mode 100755
index 0000000..747b837
--- /dev/null
+++ b/main.css
@@ -0,0 +1,152 @@
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+html {
+ height: 100%;
+}
+body {
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ background-color: #666;
+}
+a {
+ color: #bce;
+ text-decoration: none;
+}
+:link, :visited {
+ color: #bce;
+}
+select {
+ width: 150px;
+ /*font-size: 0.6em;*/
+ font-weight: normal;
+ padding-top: 0.2em;
+}
+input {
+ width: 150px;
+ text-align: center;
+ border: 1px solid black;
+}
+input[type = "submit"] {
+ background-color: black;
+ color: white;
+ border: 1px solid white;
+}
+input[type = "checkbox"] {
+ width: auto;
+}
+#main {
+ height: 100%;
+ margin-right: 165px;
+}
+#map-canvas {
+ height: 100%;
+}
+#menu {
+ font-family: Verdana, sans-serif;
+ font-size: 0.6em;
+ font-weight: bold;
+ color: white;
+ float: right;
+ width: 165px;
+ height: 100%;
+ background-color: #666;
+}
+#menu-content {
+ padding: 10px;
+}
+#footer {
+ position: fixed;
+ bottom:0;
+ padding: 10px;
+ background-color: #666;
+ color: lightgray;
+}
+#user, #trip, #summary, #export, #other {
+ padding-bottom: 10px;
+}
+#login {
+ font-family: Verdana, sans-serif;
+ position: relative;
+ top: 10%;
+ background-color: #444;
+ width: 30%;
+ min-width: 200px;
+ margin: auto;
+ padding: 30px;
+ font-size: 0.8em;
+ text-align: center;
+ color: white;
+}
+#title {
+ font-size: 1.3em;
+ padding-bottom: 0.5em;
+ padding-top: 0.6em;
+}
+#subtitle {
+ padding-bottom: 2em;
+}
+#error {
+ padding-top: 1.2em;
+ color: yellow;
+}
+#popup {
+ width:350px;
+ height:150px;
+}
+#pheader {
+ font-weight: bolder;
+ padding-bottom: 5px;
+ border-bottom: 1px solid gray;
+}
+#pleft,#pright {
+ float:left;
+ padding-top: 5px;
+}
+#pleft {
+ padding-right: 20px;
+}
+#pfooter {
+ clear: both;
+ font-size: smaller;
+ padding-top: 20px;
+}
+#bottom {
+ display: none;
+}
+#chart {
+ position: fixed;
+ bottom: 0; left:0; right: 0;
+ height: 200px;
+ margin-right: 165px;
+ background-color: white;
+ opacity: 0.8;
+}
+#close {
+ position: absolute;
+ bottom: 175px;
+ right: 175px;
+ z-index: 100;
+ font-family: Verdana, sans-serif;
+ font-size: 0.8em;
+}
+
+#close a, #close:link, #close:visited {
+ color: #5070af;
+}
diff --git a/main.js b/main.js
new file mode 100755
index 0000000..ab4e094
--- /dev/null
+++ b/main.js
@@ -0,0 +1,412 @@
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+// google maps
+function displayTrack(xml,update) {
+ altitudes.length = 0;
+ var totalMeters = 0;
+ var totalSeconds = 0;
+ // init polyline
+ var poly = new google.maps.Polyline(polyOptions);
+ poly.setMap(map);
+ var path = poly.getPath();
+ var latlngbounds = new google.maps.LatLngBounds( );
+ var positions = xml.getElementsByTagName('position');
+ var posLen = positions.length;
+ for (var i=0; i<posLen; i++) {
+ var p = parsePosition(positions[i]);
+ totalMeters += p.distance;
+ totalSeconds += p.seconds;
+ p['totalMeters'] = totalMeters;
+ p['totalSeconds'] = totalSeconds;
+ p['coordinates'] = new google.maps.LatLng(p.latitude,p.longitude);
+ // set marker
+ setMarker(p,i,posLen);
+ // update polyline
+ path.push(p.coordinates);
+ latlngbounds.extend(p.coordinates);
+ // save altitudes for chart
+ altitudes[i] = p.altitude;
+ }
+ if (update) {
+ map.fitBounds(latlngbounds);
+ if (i==1) {
+ // only one point, zoom out
+ zListener =
+ google.maps.event.addListenerOnce(map, 'bounds_changed', function(event) {
+ if (this.getZoom()){
+ this.setZoom(15);
+ }
+ });
+ setTimeout(function(){google.maps.event.removeListener(zListener)}, 2000);
+ }
+ }
+ latestTime = p.dateoccured;
+ polies.push(poly);
+
+ updateSummary(p.dateoccured,totalMeters,totalSeconds);
+ if (p.tid!=trackid) {
+ trackid=p.tid;
+ setTrack(trackid);
+ }
+ if (document.getElementById('bottom').style.display=='block') {
+ // update altitudes chart
+ chart.clearChart();
+ displayChart();
+ }
+}
+
+function clearMap(){
+ if (polies){
+ for (var i=0; i<polies.length; i++){
+ polies[i].setMap(null);
+ }
+ }
+ if (markers){
+ for (var i=0; i<markers.length; i++){
+ google.maps.event.removeListener(popups[i].listener);
+ popups[i].setMap(null);
+ markers[i].setMap(null);
+ }
+ }
+ markers.length = 0;
+ polies.length = 0;
+ popups.lentgth = 0;
+}
+
+var popup;
+function setMarker(p,i,posLen) {
+ // marker
+ var marker = new google.maps.Marker( {
+ map: map,
+ position: p.coordinates,
+ title: p.dateoccured
+ });
+ if (latest==1) { marker.setIcon('http://maps.google.com/mapfiles/dd-end.png') }
+ else if (i==0) { marker.setIcon('http://maps.google.com/mapfiles/marker_greenA.png') }
+ else if (i==posLen-1) { marker.setIcon('http://maps.google.com/mapfiles/markerB.png') }
+ else { marker.setIcon('http://labs.google.com/ridefinder/images/mm_20_gray.png') }
+ // popup
+ var content = '<div id="popup">'+
+ '<div id="pheader">'+lang_user+': '+p.username.toUpperCase()+'<br />'+lang_track+': '+p.trackname.toUpperCase()+
+ '</div>'+
+ '<div id="pbody">'+
+ '<div id="pleft"><b>'+lang_time+':</b> '+p.dateoccured+'<br />'+
+ ((p.speed != null)?'<b>'+lang_speed+':</b> '+(p.speed.toKmH()*factor_kmh)+' '+unit_kmh+'<br />':'')+
+ ((p.altitude != null)?'<b>'+lang_altitude+':</b> '+(p.altitude*factor_m).toFixed()+' '+unit_m+'<br />':'')+'</div>'+
+ ((latest==0)?
+ ('<div id="pright"><b>'+lang_ttime+':</b> '+p.totalSeconds.toHMS()+'<br />'+
+ '<b>'+lang_aspeed+':</b> '+((p.totalSeconds>0)?((p.totalMeters/p.totalSeconds).toKmH()*factor_kmh).toFixed():0)+' '+unit_kmh+'<br />'+
+ '<b>'+lang_tdistance+':</b> '+(p.totalMeters.toKm()*factor_km).toFixed(2)+' '+unit_km+'<br />'+'</div>'):'')+
+ '<div id="pfooter">'+lang_point+' '+(i+1)+' '+lang_of+' '+(posLen)+'</div>'+
+ '</div></div>';
+ popup = new google.maps.InfoWindow();
+ popup.listener = google.maps.event.addListener(marker, 'click', (function(marker,content) {
+ return function() {
+ popup.setContent(content);
+ popup.open(map, marker);
+ if (document.getElementById('bottom').style.display=='block') {
+ chart.setSelection([{row:i,column:null}]);
+ }
+ }
+ })(marker,content));
+ markers.push(marker);
+ popups.push(popup);
+}
+
+
+
+// openstreetmaps
+// TODO
+
+
+// general stuff
+if (units=='imperial') {
+ factor_kmh = 0.62; //to mph
+ unit_kmh = 'mph';
+ factor_m = 3.28; // to feet
+ unit_m = 'ft';
+ factor_km = 0.62; // to miles
+ unit_km = 'mi';
+}
+else {
+ factor_kmh = 1;
+ unit_kmh = 'km/h';
+ factor_m = 1;
+ unit_m = 'm';
+ factor_km = 1;
+ unit_km = 'km';
+}
+var latest = 0;
+var latestTime = 0;
+var live = 0;
+var chart;
+var altitudes = new Array();
+var altTimeout;
+function displayChart() {
+ if (chart) { google.visualization.events.removeAllListeners(chart); }
+ var data = new google.visualization.DataTable();
+ data.addColumn('number', 'id');
+ data.addColumn('number', 'altitude');
+ var altLen = altitudes.length;
+ for (var i=0; i<altLen; i++) {
+ data.addRow([(i+1),Math.round((altitudes[i]*factor_m))]);
+ }
+
+ var options = {
+ title: lang_altitude+' ('+unit_m+')',
+ hAxis: { textPosition: 'none' },
+ legend: { position: 'none' }
+ };
+
+ chart = new google.visualization.LineChart(document.getElementById('chart'));
+ chart.draw(data, options);
+
+ google.visualization.events.addListener(chart, 'select', function() {
+ if (popup) {popup.close(); clearTimeout(altTimeout);}
+ var selection = chart.getSelection()[0];
+ if (selection) {
+ var id = selection.row;
+ var contentString = '<div style="width:40px; height:20px;padding:10px">'+Math.round(altitudes[id]*factor_m)+' '+unit_m+'</div>';
+ popup = new google.maps.InfoWindow({
+ content: contentString
+ });
+ popup.open(map,markers[id]);
+ altTimeout = setTimeout(function() { if (popup) {popup.close();} },2000);
+ }
+ });
+}
+
+function toggleChart(i) {
+ var altLen = altitudes.length;
+ if (altLen<=1) { return; }
+ var e = document.getElementById('bottom');
+ if (arguments.length < 1) {
+ if (e.style.display == 'block') { i = 0 }
+ else { i = 1; }
+ }
+ if (i==0) {
+ chart.clearChart();
+ e.style.display = 'none';
+ }
+ else {
+ e.style.display = 'block';
+ displayChart();
+ }
+}
+
+function getXHR() {
+ var xmlhttp = null;
+ if (window.XMLHttpRequest) {
+ xmlhttp=new XMLHttpRequest();
+ }
+ else {
+ xmlhttp=new ActiveXObject('Microsoft.XMLHTTP');
+ }
+ return xmlhttp;
+}
+
+function loadTrack(userid,trackid,update) {
+ if (latest==1) { trackid=0; }
+ var xhr = getXHR();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState==4 && xhr.status==200) {
+ var xml = xhr.responseXML;
+ var positions = xml.getElementsByTagName('position');
+ if (positions.length>0) {
+ clearMap();
+ displayTrack(xml,update);
+ }
+ xhr = null;
+ }
+ }
+ xhr.open('GET','getpositions.php?trackid='+trackid+'&userid='+userid,true);
+ xhr.send();
+}
+
+function parsePosition(p) {
+ // read data
+ var latitude = getNode(p,'latitude');
+ var longitude = getNode(p,'longitude');
+ var altitude = getNode(p,'altitude'); // may be null
+ if (altitude != null) { altitude = parseInt(altitude); }
+ var speed = getNode(p,'speed'); // may be null
+ if (speed != null) { speed = parseInt(speed); }
+ var angle = getNode(p,'angle'); // may be null
+ if (angle != null) { angle = parseInt(angle); }
+ var username = getNode(p,'username');
+ var trackname = getNode(p,'trackname');
+ var tid = getNode(p,'trackid');
+ var dateoccured = getNode(p,'dateoccured');
+ var distance = parseInt(getNode(p,'distance'));
+ var seconds = parseInt(getNode(p,'seconds'));
+ return {
+ 'latitude': latitude,
+ 'longitude': longitude,
+ 'altitude': altitude,
+ 'speed': speed,
+ 'angle': angle,
+ 'username': username,
+ 'trackname': trackname,
+ 'tid': tid,
+ 'dateoccured': dateoccured,
+ 'distance': distance,
+ 'seconds': seconds
+ };
+}
+
+function load(type,userid,trackid) {
+ var url = 'download.php?type='+type+'&userid='+userid+'&trackid='+trackid;
+ window.location.assign(url);
+}
+
+function updateSummary(l,d,s) {
+ var t = document.getElementById('summary');
+ if (latest==0){
+ t.innerHTML = '<u>'+lang_summary+'</u><br />'+
+ lang_tdistance+': '+(d.toKm()*factor_km).toFixed(2)+' '+unit_km+'<br />'+
+ lang_ttime+': '+s.toHMS();
+ }
+ else {
+ t.innerHTML = '<u>'+lang_latest+':</u><br />'+l;
+ }
+}
+
+function getNode(p,name) {
+ return ((p.getElementsByTagName(name)[0].childNodes[0]) ? p.getElementsByTagName(name)[0].childNodes[0].nodeValue : null);
+}
+
+
+// seconds to (d) H:M:S
+Number.prototype.toHMS = function(){
+ var s = this;
+ var d = Math.floor(s / 86400);
+ var h = Math.floor((s % 86400) / 3600);
+ var m = Math.floor(((s % 86400) % 3600) / 60);
+ s = ((s % 86400) % 3600) % 60;
+
+ return ((d>0)?(d + ' d '):'') + (('00'+h).slice(-2)) + ':' + (('00'+m).slice(-2)) + ':' + (('00'+s).slice(-2)) + '';
+}
+// meters to km
+Number.prototype.toKm = function() {
+ return Math.round(this/10)/100;
+}
+// m/s to km/h
+Number.prototype.toKmH = function() {
+ return Math.round(this*3600/10)/100;
+}
+
+// negate value
+function toggleLatest() {
+ if (latest==0) {
+ latest = 1;
+ loadTrack(userid,0,1);
+ }
+ else {
+ latest = 0;
+ loadTrack(userid,trackid,1);
+ }
+}
+
+function setTrack(t) {
+ document.getElementsByName('track')[0].value = t;
+}
+
+function selectTrack(f) {
+ trackid=f.options[f.selectedIndex].value;
+ document.getElementById('latest').checked = false;
+ if (latest==1) { toggleLatest(); }
+ loadTrack(userid,trackid,1);
+}
+
+function selectUser(f) {
+ userid=f.options[f.selectedIndex].value;
+ if (f.options[0].disabled==false) {
+ f.options[0].disabled = true;
+ }
+ document.getElementById('latest').checked = false;
+ if (latest==1) { toggleLatest(); }
+ getTrips(userid);
+}
+
+function getTrips(userid) {
+ var xhr = getXHR();
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState==4 && xhr.status==200) {
+ var xml = xhr.responseXML;
+ var trips = xml.getElementsByTagName('trip');
+ if (trips.length>0) {
+ fillOptions(xml);
+ }
+ xhr = null;
+ }
+ }
+ xhr.open('GET','gettrips.php?userid='+userid,true);
+ xhr.send();
+}
+
+function fillOptions(xml) {
+ var trackSelect = document.getElementsByName('track')[0];
+ clearOptions(trackSelect);
+ var trips = xml.getElementsByTagName('trip');
+ var trpLen = trips.length;
+ for (var i=0; i<trpLen; i++) {
+ var trackid = getNode(trips[i],'trackid');
+ var trackname = getNode(trips[i],'trackname');
+ var option = document.createElement("option");
+ option.value = trackid;
+ option.innerHTML = trackname;
+ trackSelect.appendChild(option);
+ }
+ var defaultTrack = getNode(trips[0],'trackid');
+ loadTrack(userid,defaultTrack,1);
+}
+
+function clearOptions(el){
+ if (el.options) {
+ while (el.options.length) {
+ el.remove(0);
+ }
+ }
+}
+
+var auto;
+function autoReload() {
+ if (live==0) {
+ live = 1;
+ auto = setInterval(function() { loadTrack(userid,trackid,0); },interval*1000);
+ }
+ else {
+ live = 0;
+ clearInterval(auto);
+ }
+}
+
+function setTime() {
+ var i = parseInt(prompt(lang_newinterval));
+ if (!isNaN(i) && i!=interval) {
+ interval = i;
+ document.getElementById('auto').innerHTML = interval;
+ // if live tracking on, reload with new interval
+ if (live==1) {
+ live = 0;
+ clearInterval(auto);
+ autoReload();
+ }
+ }
+}
diff --git a/requests.php b/requests.php
new file mode 100755
index 0000000..38a0168
--- /dev/null
+++ b/requests.php
@@ -0,0 +1,268 @@
+<?php
+/* phpTrackme
+ *
+ * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net)
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+// TrackMe API
+// http://forum.xda-developers.com/showpost.php?p=3250539&postcount=2
+
+require_once("config.php");
+$user = (isset($_REQUEST['u']) ? $_REQUEST['u'] : "");
+$pass = (isset($_REQUEST['p']) ? md5($salt.$_REQUEST['p']) : "");
+$requireddb = (isset($_REQUEST['db']) ? $_REQUEST['db'] : 0);
+$tripname = (isset($_REQUEST['tn']) ? $_REQUEST['tn'] : "");
+$action = (isset($_REQUEST['a']) ? $_REQUEST['a'] : "");
+
+// FIXME what is it for?
+if ($requireddb<8) {
+ //Result:5 Incompatible database.
+ quit(5);
+}
+
+$mysqli = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
+if ($mysqli->connect_errno) {
+ //Result:4 Unable to connect database.
+ quit(4);
+}
+
+if ((!$user) || (!$pass)){
+ //Result:3 User or password not specified.
+ quit(3);
+}
+
+$query = $mysqli->prepare("SELECT ID,username,password FROM users WHERE username=? LIMIT 1");
+$query->bind_param('s', $user);
+$query->execute();
+$query->store_result();
+$query->bind_result($userid, $rec_user, $rec_pass);
+$query->fetch();
+$num = $query->num_rows;
+$query->free_result();
+$query->close();
+if ($num) {
+ if (($user==$rec_user) && ($pass!=$rec_pass)) {
+ //Result:1 User correct, invalid password.
+ quit(1);
+ }
+}
+else {
+ if ($allow_registration) {
+ // User unknown, let's create it
+ $query = $mysqli->prepare("INSERT INTO users (username,password) VALUES (?,?)");
+ $query->bind_param('ss', $user, $pass);
+ $query->execute();
+ $userid = $mysqli->insert_id;
+ $query->close();
+ if (!$userid) {
+ //Result:2 User did not exist but after being created couldn't be found.
+ // Or rather something went wrong while updating database
+ quit(2);
+ }
+ }
+ else {
+ // User unknown, we don't allow autoregistration
+ // Let's use this one:
+ //Result:1 User correct, invalid password.
+ quit(1);
+ }
+}
+
+switch($action) {
+ // action: noop
+ case "noop":
+ // test
+ quit(0);
+ break;
+
+ // action: deletetrip
+ case "deletetrip":
+ if ($tripname) {
+ $sql = "DELETE FROM positions LEFT JOIN trips ON positions.FK_Trips_ID=trips.ID "
+ ."WHERE positions.FK_Users_ID=? AND trips.Name=?";
+ $query = $mysqli->prepare($sql);
+ if ($query) {
+ $query->bind_param('is', $userid, $tripname);
+ $query->execute();
+ $query->close();
+ }
+ $sql = "DELETE FROM trips WHERE FK_Users_ID=? AND Name=?";
+ $query = $mysqli->prepare($sql);
+ $query->bind_param('is', $userid, $tripname);
+ $query->execute();
+ $rows = $mysqli->affected_rows;
+ $query->close();
+ if ($rows) {
+ quit(0);
+ }
+ else {
+ //Result:7 Trip not found
+ quit(7);
+ }
+ }
+ else {
+ //Result:6 Trip not specified.
+ quit(6);
+ }
+ break;
+
+ // action: addtrip
+ case "addtrip":
+ if ($tripname) {
+ $sql = "INSERT INTO trips (FK_Users_ID,Name) VALUES (?,?)";
+ $query = $mysqli->prepare($sql);
+ $query->bind_param('is', $userid, $tripname);
+ $query->execute();
+ $query->close();
+ }
+ else {
+ //Result:6 Trip not specified.
+ quit(6);
+ }
+ break;
+
+ // action: gettriplist
+ case "gettriplist":
+ $sql = "SELECT a1.Name,(SELECT MIN(a2.DateOccurred) FROM positions a2 "
+ ."WHERE a2.FK_Trips_ID=a1.ID) AS startdate "
+ ."FROM trips a1 WHERE a1.FK_Users_ID=? ORDER BY Name";
+ $query = $mysqli->prepare($sql);
+ $query->bind_param('i', $userid);
+ $query->execute();
+ $query->store_result();
+ $query->bind_result($tripname,$startdate);
+ $num = $query->num_rows;
+ $triplist = array();
+ if ($num) {
+ while ($query->fetch()) {
+ $triplist[] = $tripname."|".$startdate;
+ }
+ }
+ $query->free_result();
+ $query->close();
+ $param = implode("\n",$triplist);
+ quit(0,$param);
+ break;
+
+ // action: upload
+ case "upload":
+ $lat = isset($_REQUEST["lat"]) ? $_REQUEST["lat"] : NULL;
+ $long = isset($_REQUEST["long"]) ? $_REQUEST["long"] : NULL;
+ $dateoccurred = isset($_REQUEST["do"]) ? $_REQUEST["do"] : NULL;
+ $altitude = isset($_REQUEST["alt"]) ? $_REQUEST["alt"] : NULL;
+ $angle = isset($_REQUEST["ang"]) ? $_REQUEST["ang"] : NULL;
+ $speed = isset($_REQUEST["sp"]) ? $_REQUEST["sp"] : NULL;
+ $iconname = isset($_REQUEST["iconname"]) ? $_REQUEST["iconname"] : NULL;
+ $comments = isset($_REQUEST["comments"]) ? $_REQUEST["comments"] : NULL;
+ $imageurl = isset($_REQUEST["imageurl"]) ? $_REQUEST["imageurl"] : NULL;
+ $cellid = isset($_REQUEST["cid"]) ? $_REQUEST["cid"] : NULL;
+ $signalstrength = isset($_REQUEST["ss"]) ? $_REQUEST["ss"] : NULL;
+ $signalstrengthmax = isset($_REQUEST["ssmax"]) ? $_REQUEST["ssmax"] : NULL;
+ $signalstrengthmin = isset($_REQUEST["ssmin"]) ? $_REQUEST["ssmin"] : NULL;
+ $batterystatus = isset($_REQUEST["bs"]) ? $_REQUEST["bs"] : NULL;
+ $uploadss = isset($_REQUEST["upss"]) ? $_REQUEST["upss"] : NULL; // FIXME is it needed?
+ $iconid = NULL;
+ if ($iconname) {
+ $sql = "SELECT ID FROM icons WHERE Name=? LIMIT 1";
+ $query = $mysqli->prepare($sql);
+ $query->bind_param('s', $iconname);
+ $query->execute();
+ $query->store_result();
+ $query->bind_result($id);
+ $query->fetch();
+ $num = $query->num_rows;
+ $query->free_result();
+ $query->close();
+ if ($num) {
+ $iconid = $id;
+ }
+ }
+ $tripid = NULL; // FIXME: not sure what trips with null id are
+ if ($tripname) {
+ // get tripid
+ $query = $mysqli->prepare("SELECT ID FROM trips WHERE FK_Users_ID=? AND Name=? LIMIT 1");
+ $query->bind_param('is', $userid, $tripname);
+ $query->execute();
+ $query->store_result();
+ $query->bind_result($tripid);
+ $query->fetch();
+ $num = $query->num_rows;
+ $query->free_result();
+ $query->close();
+ if (!$num) {
+ // create trip
+ $query = $mysqli->prepare("INSERT INTO trips (FK_Users_ID,Name) VALUES (?,?)");
+ $query->bind_param('is', $userid, $tripname);
+ $query->execute();
+ $tripid = $mysqli->insert_id;
+ $query->close();
+ if (!$tripid) {
+ //Result:6 Trip didn't exist and system was unable to create it.
+ quit(6);
+ }
+ }
+ }
+ $sql = "INSERT INTO positions "
+ ."(FK_Users_ID,FK_Trips_ID,Latitude,Longitude,DateOccurred,FK_Icons_ID,"
+ ."Speed,Altitude,Comments,ImageURL,Angle,SignalStrength,SignalStrengthMax,"
+ ."SignalStrengthMin,BatteryStatus) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
+ $query = $mysqli->prepare($sql);
+ $query->bind_param('iiddsiddssdiiii',
+ $userid,$tripid,$lat,$long,$dateoccurred,$iconid,
+ $speed,$altitude,$comments,$imageurl,$angle,$signalstrength,$signalstrengthmax,
+ $signalstrengthmin,$batterystatus);
+ $query->execute();
+ $query->close();
+ if ($mysqli->errno) {
+ //Result:7|SQLERROR Insert statement failed.
+ quit(7,$mysqli->error);
+ }
+ //FIXME Are cellids used in Android client?
+ $upcellext = isset($_REQUEST["upcellext"]) ? $_REQUEST["upcellext"] : NULL;
+ if ($upcellext==1 && $cellid) {
+ $sql = "INSERT INTO cellids (CellID,Latitude,Longitude,SignalStrength,SignalStrengthMax,SignalStrengthMin) "
+ ."VALUES (?,?,?,?,?,?)";
+ $query = $mysqli->prepare($sql);
+ $query->bind_param('sddiii',$cellid,$lat,$long,$signalstrength,$signalstrengthmax,$signalstrengthmin);
+ $query->execute();
+ $query->close();
+ if ($mysqli->errno) {
+ //Result:7|SQLERROR Insert statement failed.
+ quit(7,$mysqli->error);
+ }
+ }
+ quit(0);
+ break;
+
+ // action: geticonlist
+ // action: renametrip
+ // action: findclosestbuddy
+ // action: delete
+ // action: sendemail
+ // action: updateimageurl
+ // action: findclosestpositionbytime
+ // action: findclosestpositionbyposition
+ // action: gettripinfo
+ // action: gettriphighlights
+}
+
+function quit($errno,$param=""){
+ print "Result:".$errno.(($param)?"|$param":"");
+ exit();
+}
+
+$mysqli->close();
+?>
diff --git a/trackme.sql b/trackme.sql
new file mode 100755
index 0000000..0559277
--- /dev/null
+++ b/trackme.sql
@@ -0,0 +1,128 @@
+SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
+SET time_zone = "+00:00";
+CREATE DATABASE IF NOT EXISTS `trackme` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
+USE `trackme`;
+
+CREATE TABLE IF NOT EXISTS `cellids` (
+ `ID` int(11) NOT NULL auto_increment,
+ `CellID` varchar(255) NOT NULL,
+ `Latitude` double NOT NULL,
+ `Longitude` double NOT NULL,
+ `DateAdded` timestamp NOT NULL default CURRENT_TIMESTAMP,
+ `SignalStrength` int(11) default NULL,
+ `SignalStrengthMax` int(11) default NULL,
+ `SignalStrengthMin` int(11) default NULL,
+ PRIMARY KEY (`ID`),
+ KEY `Index_CellID` (`CellID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `icons` (
+ `ID` int(11) NOT NULL auto_increment,
+ `Name` varchar(255) NOT NULL,
+ `URL` varchar(512) NOT NULL,
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `positions` (
+ `ID` int(11) NOT NULL auto_increment,
+ `FK_Users_ID` int(11) NOT NULL,
+ `FK_Trips_ID` int(11) default NULL,
+ `FK_Icons_ID` int(11) default NULL,
+ `Latitude` double NOT NULL,
+ `Longitude` double NOT NULL,
+ `Altitude` double default '0',
+ `Speed` double default '0',
+ `Angle` double default NULL,
+ `DateAdded` timestamp NOT NULL default CURRENT_TIMESTAMP,
+ `DateOccurred` timestamp NULL default '0000-00-00 00:00:00',
+ `Comments` varchar(255) default NULL,
+ `ImageURL` varchar(255) default NULL,
+ `SignalStrength` int(11) default NULL,
+ `SignalStrengthMax` int(11) default NULL,
+ `SignalStrengthMin` int(11) default NULL,
+ `BatteryStatus` tinyint(4) default NULL,
+ PRIMARY KEY (`ID`),
+ KEY `Index_FK_Trips_ID` (`FK_Trips_ID`),
+ KEY `Index_FK_Users_ID` (`FK_Users_ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `trips` (
+ `ID` int(11) NOT NULL auto_increment,
+ `FK_Users_ID` int(11) NOT NULL,
+ `Name` varchar(255) NOT NULL,
+ `Comments` varchar(1024) default NULL,
+ PRIMARY KEY (`ID`),
+ UNIQUE KEY `Index_FK_Users_ID_Name` (`FK_Users_ID`,`Name`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `users` (
+ `ID` int(11) NOT NULL auto_increment,
+ `username` varchar(15) NOT NULL,
+ `password` varchar(50) NOT NULL default '',
+ PRIMARY KEY (`ID`),
+ UNIQUE KEY `Index_username` (`username`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+INSERT INTO `icons` VALUES (1, 'Snack', 'http://maps.google.com/mapfiles/ms/micons/snack_bar.png');
+INSERT INTO `icons` VALUES (2, 'Hiking', 'http://maps.google.com/mapfiles/ms/micons/hiker.png');
+INSERT INTO `icons` VALUES (3, 'Lodging', 'http://maps.google.com/mapfiles/ms/micons/lodging.png');
+INSERT INTO `icons` VALUES (4, 'Restaurant', 'http://maps.google.com/mapfiles/ms/micons/restaurant.png');
+INSERT INTO `icons` VALUES (5, 'POI', 'http://maps.google.com/mapfiles/ms/micons/POI.png');
+INSERT INTO `icons` VALUES (6, 'Arts', 'http://maps.google.com/mapfiles/ms/micons/arts.png');
+INSERT INTO `icons` VALUES (7, 'Bar', 'http://maps.google.com/mapfiles/ms/micons/bar.png');
+INSERT INTO `icons` VALUES (8, 'Blue-dot', 'http://maps.google.com/mapfiles/ms/micons/blue-dot.png');
+INSERT INTO `icons` VALUES (9, 'Bus', 'http://maps.google.com/mapfiles/ms/micons/bus.png');
+INSERT INTO `icons` VALUES (10, 'Taxi', 'http://maps.google.com/mapfiles/ms/micons/cabs.png');
+INSERT INTO `icons` VALUES (11, 'Camera', 'http://maps.google.com/mapfiles/ms/micons/camera.png');
+INSERT INTO `icons` VALUES (12, 'Camping', 'http://maps.google.com/mapfiles/ms/micons/campground.png');
+INSERT INTO `icons` VALUES (13, 'Caution', 'http://maps.google.com/mapfiles/ms/micons/caution.png');
+INSERT INTO `icons` VALUES (14, 'Coffee House', 'http://maps.google.com/mapfiles/ms/micons/coffeehouse.png');
+INSERT INTO `icons` VALUES (15, 'Store', 'http://maps.google.com/mapfiles/ms/micons/convienancestore.png');
+INSERT INTO `icons` VALUES (16, 'Cycling', 'http://maps.google.com/mapfiles/ms/micons/cycling.png');
+INSERT INTO `icons` VALUES (17, 'Dollar', 'http://maps.google.com/mapfiles/ms/micons/dollar.png');
+INSERT INTO `icons` VALUES (18, 'Drinking water', 'http://maps.google.com/mapfiles/ms/micons/drinking_water.png');
+INSERT INTO `icons` VALUES (19, 'Electronics', 'http://maps.google.com/mapfiles/ms/micons/electronics.png');
+INSERT INTO `icons` VALUES (20, 'Falling Rocks', 'http://maps.google.com/mapfiles/ms/micons/fallingrocks.png');
+INSERT INTO `icons` VALUES (21, 'Ferry', 'http://maps.google.com/mapfiles/ms/micons/ferry.png');
+INSERT INTO `icons` VALUES (22, 'Fire Dept.', 'http://maps.google.com/mapfiles/ms/micons/firedept.png');
+INSERT INTO `icons` VALUES (23, 'Fishing', 'http://maps.google.com/mapfiles/ms/micons/fishing.png');
+INSERT INTO `icons` VALUES (24, 'Flag', 'http://maps.google.com/mapfiles/ms/micons/flag.png');
+INSERT INTO `icons` VALUES (25, 'Gas', 'http://maps.google.com/mapfiles/ms/micons/gas.png');
+INSERT INTO `icons` VALUES (26, 'Grocery Store', 'http://maps.google.com/mapfiles/ms/micons/grocerystore.png');
+INSERT INTO `icons` VALUES (27, 'Helicopter', 'http://maps.google.com/mapfiles/ms/micons/helicopter.png');
+INSERT INTO `icons` VALUES (28, 'Horseback riding', 'http://maps.google.com/mapfiles/ms/micons/horsebackriding.png');
+INSERT INTO `icons` VALUES (29, 'Hospital', 'http://maps.google.com/mapfiles/ms/micons/hospitals.png');
+INSERT INTO `icons` VALUES (30, 'Hot springs', 'http://maps.google.com/mapfiles/ms/micons/hotsprings.png');
+INSERT INTO `icons` VALUES (31, 'Info', 'http://maps.google.com/mapfiles/ms/micons/info.png');
+INSERT INTO `icons` VALUES (32, 'Info 2', 'http://maps.google.com/mapfiles/ms/micons/info_circle.png');
+INSERT INTO `icons` VALUES (33, 'Man', 'http://maps.google.com/mapfiles/ms/micons/man.png');
+INSERT INTO `icons` VALUES (34, 'Marina', 'http://maps.google.com/mapfiles/ms/micons/marina.png');
+INSERT INTO `icons` VALUES (35, 'Mechanic', 'http://maps.google.com/mapfiles/ms/micons/mechanic.png');
+INSERT INTO `icons` VALUES (36, 'Motorcycling', 'http://maps.google.com/mapfiles/ms/micons/motorcycling.png');
+INSERT INTO `icons` VALUES (37, 'Parking', 'http://maps.google.com/mapfiles/ms/micons/parkinglot.png');
+INSERT INTO `icons` VALUES (38, 'Partly Cloudy', 'http://maps.google.com/mapfiles/ms/micons/partly_cloudy.png');
+INSERT INTO `icons` VALUES (39, 'Phone', 'http://maps.google.com/mapfiles/ms/micons/phone.png');
+INSERT INTO `icons` VALUES (40, 'Picnic', 'http://maps.google.com/mapfiles/ms/micons/picnic.png');
+INSERT INTO `icons` VALUES (41, 'Plane', 'http://maps.google.com/mapfiles/ms/micons/plane.png');
+INSERT INTO `icons` VALUES (42, 'Police', 'http://maps.google.com/mapfiles/ms/micons/police.png');
+INSERT INTO `icons` VALUES (43, 'Post Office', 'http://maps.google.com/mapfiles/ms/micons/postoffice-us.png');
+INSERT INTO `icons` VALUES (44, 'Question mark', 'http://maps.google.com/mapfiles/ms/micons/question.png');
+INSERT INTO `icons` VALUES (45, 'Rail', 'http://maps.google.com/mapfiles/ms/micons/rail.png');
+INSERT INTO `icons` VALUES (46, 'Rainy', 'http://maps.google.com/mapfiles/ms/micons/rainy.png');
+INSERT INTO `icons` VALUES (47, 'Ranger Station', 'http://maps.google.com/mapfiles/ms/micons/rangerstation.png');
+INSERT INTO `icons` VALUES (48, 'Recycle', 'http://maps.google.com/mapfiles/ms/micons/recycle.png');
+INSERT INTO `icons` VALUES (49, 'Snow', 'http://maps.google.com/mapfiles/ms/micons/snowflake_simple.png');
+INSERT INTO `icons` VALUES (50, 'Sport', 'http://maps.google.com/mapfiles/ms/micons/sportvenue.png');
+INSERT INTO `icons` VALUES (51, 'Subway', 'http://maps.google.com/mapfiles/ms/micons/subway.png');
+INSERT INTO `icons` VALUES (52, 'Sunny', 'http://maps.google.com/mapfiles/ms/micons/sunny.png');
+INSERT INTO `icons` VALUES (53, 'Swimming', 'http://maps.google.com/mapfiles/ms/micons/swimming.png');
+INSERT INTO `icons` VALUES (54, 'Toilets', 'http://maps.google.com/mapfiles/ms/micons/toilets.png');
+INSERT INTO `icons` VALUES (55, 'Trail', 'http://maps.google.com/mapfiles/ms/micons/trail.png');
+INSERT INTO `icons` VALUES (56, 'Tree', 'http://maps.google.com/mapfiles/ms/micons/tree.png');
+INSERT INTO `icons` VALUES (57, 'Truck', 'http://maps.google.com/mapfiles/ms/micons/truck.png');
+INSERT INTO `icons` VALUES (58, 'Volcano', 'http://maps.google.com/mapfiles/ms/micons/volcano.png');
+INSERT INTO `icons` VALUES (59, 'Water', 'http://maps.google.com/mapfiles/ms/micons/water.png');
+INSERT INTO `icons` VALUES (60, 'Waterfalls', 'http://maps.google.com/mapfiles/ms/micons/waterfalls.png');
+INSERT INTO `icons` VALUES (61, 'Wheel Chair', 'http://maps.google.com/mapfiles/ms/micons/wheel_chair_accessible.png');
+INSERT INTO `icons` VALUES (62, 'Woman', 'http://maps.google.com/mapfiles/ms/micons/woman.png');
+INSERT INTO `icons` VALUES (63, 'Monster gate', 'http://img.gamespot.com/gamespot/shared/user/emblem_e3monster_s.jpg');