├── Changelog ├── LICENSE ├── README ├── README_Backitude ├── api_gmaps.js ├── api_openlayers.js ├── auth.php ├── config.php ├── download.php ├── export.php ├── getpositions.php ├── gettrips.php ├── index.php ├── lang.php ├── logout.php ├── main.css ├── main.js ├── requests.php └── trackme.sql /Changelog: -------------------------------------------------------------------------------- 1 | Changelog 2 | 3 | 2.3 admin user with access to all tracks (markcs) 4 | Backitude support (markcs) 5 | minor fixes 6 | 7 | 2.2 preferences stored in cookies 8 | display comments in popups 9 | option to hide menu 10 | 11 | 2.1 new OpenLayers layers 12 | German translation (dtrieb) 13 | minor fixes 14 | 15 | 2.0 OpenLayers support added 16 | 17 | 1.0 initial version 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Update: 2 | As I don't use trackMe client any more I stopped working on this project. 3 | Instead I develop my own server-client solution, see: 4 | https://github.com/bfabiszewski/ulogger-server 5 | ---------------------------------------------------------------------- 6 | 7 | This is a simple web viewer for GPS tracks uploaded with mobile client. 8 | It is designed to work with Android version of great app TrackMe (http://www.luisespinosa.com/trackme_eng.html), 9 | but it should be easy to adjust it for other clients (other database tables). 10 | Interface "look and feel" is based on TrackMe Display (http://forum.xda-developers.com/showthread.php?t=477394). 11 | It is possible to switch between Google Maps API and OpenLayers API with OpenStreetMap (or any other compatible base layer). 12 | It also supports Backitude client (thanks to markcs: see README_Backitude). 13 | 14 | Live demo: 15 | - http://flaa.fabiszewski.net/phptrackme/ 16 | 17 | Requirements: 18 | - PHP 5.1.2 19 | - MYSQL 4.1 20 | - browser with javascript enabled, cookies for authentication and saving preferences 21 | 22 | Features: 23 | - simple 24 | - allows live tracking 25 | - track statistics 26 | - altitudes graph 27 | - multiple users 28 | - user authentication 29 | - Google Maps API v3 30 | - OpenLayers v2 31 | - ajax 32 | - server based configuration 33 | - user preferences stored in cookies 34 | 35 | Todo 36 | - install script 37 | - custom icons 38 | - write opensource client? 39 | 40 | License 41 | - GPL 42 | -------------------------------------------------------------------------------- /README_Backitude: -------------------------------------------------------------------------------- 1 | Backitude is an Android client that is designed to capture the location 2 | of your device at configurable time intervals or whenever a position is served 3 | up by the operating system. You can grab it from https://play.google.com/store/apps/details?id=gaugler.backitude 4 | 5 | To configure Backitude to work with the custom server, you need to 6 | set the following parameters in the custom server settings: 7 | 8 | Server URL: http:///requests.php 9 | Request Type: POST 10 | Successful Response Codes: 200,201 11 | Authentication options: Credentials in POST parameters 12 | User Name: What ever you choose 13 | Password: What ever you choose 14 | Custom Field 1: upload 15 | Custom Field 2: backitude 16 | 17 | User Name: u 18 | Password: p 19 | Latitude: lat 20 | Longitude: long 21 | Accuracy: accuracy 22 | Speed: speed 23 | Altitude: alt 24 | Direction Bearing: angle 25 | Location Timestamp: 26 | Request Timestamp: do 27 | Timezone Offset: 28 | Custom Field 1: a 29 | Custom Field 2: db 30 | 31 | mysql needs to be configured by running the trackme.sql sql script file. 32 | 33 | config.php needs to be configured. 34 | 35 | Within config.php: 36 | 37 | - Use trackme as the database name. 38 | - Initially set allow_registration = 1 so Backitude can register and your user/pass is automatically created 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /api_gmaps.js: -------------------------------------------------------------------------------- 1 | /* phpTrackme 2 | * 3 | * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net) 4 | * 5 | * This is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU Library General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | */ 19 | 20 | // google maps 21 | var map; 22 | var polies = new Array(); 23 | var markers = new Array(); 24 | var popups = new Array(); 25 | var polyOptions; 26 | var mapOptions; 27 | var loadedAPI = 'gmaps'; 28 | function init() { 29 | google.maps.visualRefresh = true; 30 | polyOptions = { 31 | strokeColor: '#FF0000', 32 | strokeOpacity: 1.0, 33 | strokeWeight: 2 34 | } 35 | mapOptions = { 36 | center: new google.maps.LatLng(init_latitude,init_longitude), 37 | zoom: 8, 38 | mapTypeId: google.maps.MapTypeId.ROADMAP, 39 | scaleControl: true 40 | }; 41 | map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions); 42 | } 43 | 44 | function displayTrack(xml,update) { 45 | altitudes.length = 0; 46 | var totalMeters = 0; 47 | var totalSeconds = 0; 48 | // init polyline 49 | var poly = new google.maps.Polyline(polyOptions); 50 | poly.setMap(map); 51 | var path = poly.getPath(); 52 | var latlngbounds = new google.maps.LatLngBounds( ); 53 | var positions = xml.getElementsByTagName('position'); 54 | var posLen = positions.length; 55 | for (var i=0; i'+lang_user+': '+p.username.toUpperCase()+'
'+lang_track+': '+p.trackname.toUpperCase()+ 131 | ''+ 132 | '
'+ 133 | ((p.comments != null)?'
'+p.comments+'
':'')+ 134 | '
'+lang_time+': '+p.dateoccured+'
'+ 135 | ((p.speed != null)?''+lang_speed+': '+(p.speed.toKmH()*factor_kmh)+' '+unit_kmh+'
':'')+ 136 | ((p.altitude != null)?''+lang_altitude+': '+(p.altitude*factor_m).toFixed()+' '+unit_m+'
':'')+'
'+ 137 | ((latest==0)? 138 | ('
'+lang_ttime+': '+p.totalSeconds.toHMS()+'
'+ 139 | ''+lang_aspeed+': '+((p.totalSeconds>0)?((p.totalMeters/p.totalSeconds).toKmH()*factor_kmh).toFixed():0)+' '+unit_kmh+'
'+ 140 | ''+lang_tdistance+': '+(p.totalMeters.toKm()*factor_km).toFixed(2)+' '+unit_km+'
'+'
'):'')+ 141 | '
'+lang_point+' '+(i+1)+' '+lang_of+' '+(posLen)+'
'+ 142 | '
'; 143 | popup = new google.maps.InfoWindow(); 144 | popup.listener = google.maps.event.addListener(marker, 'click', (function(marker,content) { 145 | return function() { 146 | popup.setContent(content); 147 | popup.open(map, marker); 148 | if (document.getElementById('bottom').style.display=='block') { 149 | chart.setSelection([{row:i,column:null}]); 150 | } 151 | } 152 | })(marker,content)); 153 | markers.push(marker); 154 | popups.push(popup); 155 | } 156 | 157 | function addChartEvent(chart) { 158 | google.visualization.events.addListener(chart, 'select', function() { 159 | if (popup) {popup.close(); clearTimeout(altTimeout);} 160 | var selection = chart.getSelection()[0]; 161 | if (selection) { 162 | var id = selection.row; 163 | var icon = markers[id].getIcon(); 164 | markers[id].setIcon('//maps.google.com/mapfiles/marker_orange.png'); 165 | altTimeout = setTimeout(function() { markers[id].setIcon(icon); },2000); 166 | } 167 | }); 168 | } 169 | //((52.20105108685229, 20.789387865580238), (52.292069558807135, 21.172192736185707)) 170 | function getBounds() { 171 | var b = map.getBounds().toString(); 172 | var bounds = b.split(',',4); 173 | var lat_sw = bounds[0].replace(/\(/g,''); 174 | var lon_sw = bounds[1].replace(/[ )]/g,''); 175 | var lat_ne = bounds[2].replace(/[ (]/g,''); 176 | var lon_ne = bounds[3].replace(/[ )]/g,''); 177 | return [lon_sw,lat_sw,lon_ne,lat_ne]; 178 | } 179 | 180 | function zoomToBounds(b) { 181 | var sw = new google.maps.LatLng(b[1],b[0]); 182 | var ne = new google.maps.LatLng(b[3],b[2]); 183 | var bounds = new google.maps.LatLngBounds(sw,ne); 184 | map.fitBounds(bounds); 185 | } 186 | -------------------------------------------------------------------------------- /api_openlayers.js: -------------------------------------------------------------------------------- 1 | /* phpTrackme 2 | * 3 | * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net) 4 | * 5 | * This is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU Library General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | */ 19 | 20 | // openlayers 21 | var map; 22 | var layerTrack; 23 | var layerMarkers; 24 | var lineStyle = {strokeColor: '#FF0000', strokeOpacity: 1, strokeWidth: 2}; 25 | var wgs84; 26 | var mercator; 27 | var loadedAPI = 'openlayers'; 28 | function init() { 29 | wgs84 = new OpenLayers.Projection('EPSG:4326'); // from WGS 1984 30 | mercator = new OpenLayers.Projection('EPSG:900913'); // to Mercator 31 | var options = { controls: [ 32 | new OpenLayers.Control.ArgParser(), // default 33 | new OpenLayers.Control.Attribution(), // default 34 | new OpenLayers.Control.LayerSwitcher(), 35 | new OpenLayers.Control.Navigation(), // default 36 | new OpenLayers.Control.PanZoomBar(),// do we need it? 37 | new OpenLayers.Control.ScaleLine() 38 | ] 39 | }; 40 | map = new OpenLayers.Map('map-canvas', options); 41 | // default layer: OpenStreetMap 42 | var mapnik = new OpenLayers.Layer.OSM('OpenStreetMap', 43 | ['//a.tile.openstreetmap.org/${z}/${x}/${y}.png', 44 | '//b.tile.openstreetmap.org/${z}/${x}/${y}.png', 45 | '//c.tile.openstreetmap.org/${z}/${x}/${y}.png']); 46 | map.addLayer(mapnik); 47 | if (layer_ocm==1) { 48 | // OpenCycleMap 49 | var ocm = new OpenLayers.Layer.OSM('OpenCycleMap', 50 | ['//a.tile.thunderforest.com/cycle/${z}/${x}/${y}.png', 51 | '//b.tile.thunderforest.com/cycle/${z}/${x}/${y}.png', 52 | '//c.tile.thunderforest.com/cycle/${z}/${x}/${y}.png']); 53 | map.addLayer(ocm); 54 | } 55 | if (layer_mq==1) { 56 | // MapQuest-OSM 57 | var mq = new OpenLayers.Layer.OSM('MapQuest-OSM', 58 | ['//otile1.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.jpg', 59 | '//otile2.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.jpg', 60 | '//otile3.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.jpg', 61 | '//otile4.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.jpg']); 62 | map.addLayer(mq); 63 | } 64 | if (layer_osmapa==1) { 65 | // osmapa.pl 66 | var osmapa = new OpenLayers.Layer.OSM('osmapa.pl', 67 | ['//a.osm.trail.pl/osmapa.pl/${z}/${x}/${y}.png', 68 | '//b.osm.trail.pl/osmapa.pl/${z}/${x}/${y}.png', 69 | '//c.osm.trail.pl/osmapa.pl/${z}/${x}/${y}.png']); 70 | map.addLayer(osmapa); 71 | } 72 | if (layer_ump==1) { 73 | // UMP 74 | var ump = new OpenLayers.Layer.OSM('UMP', 75 | ['//1.tiles.ump.waw.pl/ump_tiles/${z}/${x}/${y}.png', 76 | '//2.tiles.ump.waw.pl/ump_tiles/${z}/${x}/${y}.png', 77 | '//3.tiles.ump.waw.pl/ump_tiles/${z}/${x}/${y}.png']); 78 | map.addLayer(ump); 79 | } 80 | var position = new OpenLayers.LonLat(init_longitude,init_latitude).transform(wgs84, mercator); 81 | var zoom = 8; 82 | map.setCenter(position, zoom); 83 | // init layers 84 | layerTrack = new OpenLayers.Layer.Vector('Track'); 85 | layerMarkers = new OpenLayers.Layer.Markers('Markers'); 86 | } 87 | function displayTrack(xml,update) { 88 | altitudes.length = 0; 89 | var totalMeters = 0; 90 | var totalSeconds = 0; 91 | var points = new Array(); 92 | var latlngbounds = new OpenLayers.Bounds(); 93 | var positions = xml.getElementsByTagName('position'); 94 | var posLen = positions.length; 95 | for (var i=0; i'+lang_user+': '+p.username.toUpperCase()+'
'+lang_track+': '+p.trackname.toUpperCase()+ 166 | ''+ 167 | '
'+ 168 | ((p.comments != null)?'
'+p.comments+'
':'')+ 169 | '
'+lang_time+': '+p.dateoccured+'
'+ 170 | ((p.speed != null)?''+lang_speed+': '+(p.speed.toKmH()*factor_kmh)+' '+unit_kmh+'
':'')+ 171 | ((p.altitude != null)?''+lang_altitude+': '+(p.altitude*factor_m).toFixed()+' '+unit_m+'
':'')+'
'+ 172 | ((latest==0)? 173 | ('
'+lang_ttime+': '+p.totalSeconds.toHMS()+'
'+ 174 | ''+lang_aspeed+': '+((p.totalSeconds>0)?((p.totalMeters/p.totalSeconds).toKmH()*factor_kmh).toFixed():0)+' '+unit_kmh+'
'+ 175 | ''+lang_tdistance+': '+(p.totalMeters.toKm()*factor_km).toFixed(2)+' '+unit_km+'
'+'
'):'')+ 176 | '
'+lang_point+' '+(i+1)+' '+lang_of+' '+(posLen)+'
'+ 177 | '
'; 178 | marker.events.register("mousedown", marker, (function() { 179 | return function() { 180 | // remove popups 181 | if (map.popups.length>0) { 182 | for (var j = map.popups.length-1; j>=0; j-- ) { 183 | map.removePopup(map.popups[j]) 184 | }; 185 | } 186 | // show popup 187 | var popup = new OpenLayers.Popup.FramedCloud("id "+(i+1),lonLat,null,content,icon,true); 188 | map.addPopup(popup); 189 | if (document.getElementById('bottom').style.display=='block') { 190 | chart.setSelection([{row:i,column:null}]); 191 | } 192 | } 193 | })()); 194 | } 195 | 196 | function addChartEvent(chart) { 197 | google.visualization.events.addListener(chart, 'select', function() { 198 | var selection = chart.getSelection()[0]; 199 | if (selection) { 200 | var id = selection.row; 201 | var marker = layerMarkers.markers[id]; 202 | var url = marker.icon.url; 203 | marker.setUrl('//www.openstreetmap.org/openlayers/img/marker-gold.png'); 204 | altTimeout = setTimeout(function() { marker.setUrl(url); },2000); 205 | } 206 | }); 207 | } 208 | //20.597985430276808,52.15547181298076,21.363595171488573,52.33750879522563 209 | function getBounds() { 210 | var b = map.getExtent().transform(mercator,wgs84).toString(); 211 | var bounds = b.split(',',4); 212 | var lon_sw = bounds[0]; 213 | var lat_sw = bounds[1]; 214 | var lon_ne = bounds[2]; 215 | var lat_ne = bounds[3]; 216 | return [lon_sw,lat_sw,lon_ne,lat_ne]; 217 | } 218 | 219 | function zoomToBounds(b) { 220 | var bounds = new OpenLayers.Bounds(b).transform(wgs84,mercator); 221 | map.zoomToExtent(bounds); 222 | } 223 | -------------------------------------------------------------------------------- /auth.php: -------------------------------------------------------------------------------- 1 | connect_errno) { 29 | printf("Connect failed: %s\n", $mysqli->connect_error); 30 | exit(); 31 | } 32 | $mysqli->set_charset("utf8"); 33 | $auth = NULL; 34 | $admin = NULL; 35 | if ($require_authentication) { 36 | /* authentication */ 37 | session_name('trackme'); 38 | session_start(); 39 | $sid = session_id(); 40 | 41 | $auth = (isset($_SESSION['auth']) ? $_SESSION['auth'] : ""); 42 | $admin = (isset($_SESSION['admin']) ? $_SESSION['admin'] : ""); 43 | $user = (isset($_REQUEST['user']) ? $_REQUEST['user'] : ""); 44 | $pass = (isset($_REQUEST['pass']) ? md5($salt.$_REQUEST['pass']) : ""); 45 | $ssl = ((!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == "" || $_SERVER['HTTPS'] == "off") ? "http" : "https"); 46 | $auth_error = (isset($_REQUEST['auth_error']) ? $_REQUEST['auth_error'] : 0); 47 | 48 | // not authenticated and username not submited 49 | // load form 50 | if ((!$auth) && (!$user)){ 51 | print 52 | ' 53 | 54 | 55 | '.$lang_title.' 56 | 57 | 58 | 59 | 64 | 65 | 66 |
67 |
'.$lang_title.'
68 |
'.$lang_private.'
69 |
70 | '.$lang_username.':
71 |
72 | '.$lang_password.':
73 |
74 |
75 | 76 |
77 |
'.(($auth_error==1) ? $lang_authfail : "").'
78 |
79 | 80 | '; 81 | $mysqli->close(); 82 | exit; 83 | } 84 | 85 | // username submited 86 | if ((!$auth) && ($user)){ 87 | $query = $mysqli->prepare("SELECT ID,username,password FROM users WHERE username=? LIMIT 1"); 88 | $query->bind_param('s', $user); 89 | $query->execute(); 90 | $query->bind_result($rec_ID, $rec_user, $rec_pass); 91 | $query->fetch(); 92 | $query->free_result(); 93 | //correct pass 94 | 95 | if (($user==$rec_user) && ($pass==$rec_pass)) { 96 | // login successful 97 | //delete old session 98 | $_SESSION = NULL; 99 | session_destroy(); 100 | // start new session 101 | session_name('trackme'); 102 | session_start(); 103 | if (($user==$admin_user) && ($admin_user != "")) { 104 | $_SESSION['admin'] = $admin_user; 105 | } 106 | $_SESSION['auth'] = $rec_ID; 107 | $url = str_replace("//", "/", $_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME'])."/index.php"); 108 | header("Location: $ssl://$url"); 109 | exit; 110 | } else { 111 | // unsuccessful 112 | $error = "?auth_error=1"; 113 | // destroy session 114 | $_SESSION = NULL; 115 | if (isset($_COOKIE[session_name('trackme')])) { 116 | setcookie(session_name('trackme'),'',time()-42000,'/'); 117 | } 118 | session_destroy(); 119 | $mysqli->close(); 120 | $url = str_replace("//", "/", $_SERVER['HTTP_HOST'].dirname($_SERVER['SCRIPT_NAME'])."/index.php"); 121 | header("Location: $ssl://$url$error"); 122 | exit; 123 | } 124 | } 125 | /* end of authentication */ 126 | } 127 | ?> 128 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | 80 | -------------------------------------------------------------------------------- /download.php: -------------------------------------------------------------------------------- 1 | startElement("Style"); 54 | $xml->writeAttribute("id", $name."Style"); 55 | $xml->startElement("IconStyle"); 56 | $xml->writeAttribute("id", $name."Icon"); 57 | $xml->startElement("Icon"); 58 | $xml->writeElement("href", $url); 59 | $xml->endElement(); 60 | $xml->endElement(); 61 | $xml->endElement(); 62 | } 63 | function toHMS($s) { 64 | $d = floor($s/86400); 65 | $h = floor(($s%86400)/3600); 66 | $m = floor((($s%86400)%3600)/60); 67 | $s = (($s%86400)%3600)%60; 68 | return (($d>0)?($d." d "):"").(substr("00".$h,-2)).":".(substr("00".$m,-2)).":".(substr("00".$s,-2)); 69 | } 70 | 71 | if ($trackid>0 && $userid>0) { 72 | $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"); 73 | $query->bind_param("ii", $userid, $trackid); 74 | $query->execute(); 75 | $query->store_result(); 76 | $query->bind_result($positionid,$latitude,$longitude,$altitude,$speed,$angle,$dateoccured,$username,$trackname); 77 | $query->fetch(); // take just one row to get trackname etc 78 | $query->data_seek(0); // and reset result set 79 | switch ($type) { 80 | case "kml": 81 | default: 82 | header("Content-type: application/vnd.google-earth.kml+xml"); 83 | header("Content-Disposition: attachment; filename=\"track$trackid.kml\""); 84 | $xml = new XMLWriter(); 85 | $xml->openURI("php://output"); 86 | $xml->startDocument("1.0"); 87 | $xml->startElement("kml"); 88 | $xml->writeAttribute("xmlns", "http://earth.google.com/kml/2.1"); 89 | $xml->setIndent(true); 90 | $xml->startElement("Document"); 91 | $xml->writeElement("name", $trackname); 92 | // line style 93 | $xml->startElement("Style"); 94 | $xml->writeAttribute("id", "lineStyle"); 95 | $xml->startElement("LineStyle"); 96 | $xml->writeElement("color","7f0000ff"); 97 | $xml->writeElement("width","4"); 98 | $xml->endElement(); 99 | $xml->endElement(); 100 | // marker styles 101 | addStyle($xml,"red","http://maps.google.com/mapfiles/markerA.png"); 102 | addStyle($xml,"green","http://maps.google.com/mapfiles/marker_greenB.png"); 103 | addStyle($xml,"gray","http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_gray.png"); 104 | $style = "#redStyle"; // for first element 105 | $i = 0; 106 | $totalMeters = 0; 107 | $totalSeconds = 0; 108 | while ($query->fetch()) { 109 | $distance = (isset($prev_latitude))?haversine_distance($prev_latitude,$prev_longitude,$latitude,$longitude):0; 110 | $prev_latitude = $latitude; 111 | $prev_longitude = $longitude; 112 | $seconds = (isset($prev_dateoccured))?(strtotime($dateoccured)-strtotime($prev_dateoccured)):0; 113 | $prev_dateoccured = $dateoccured; 114 | $totalMeters += $distance; 115 | $totalSeconds += $seconds; 116 | 117 | if(++$i == $query->num_rows) { $style = "#greenStyle"; } // last element 118 | $xml->startElement("Placemark"); 119 | $xml->writeAttribute("id", $positionid); 120 | //$xml->writeElement("name", $i); 121 | $description = 122 | "
".$lang_user.": ".strtoupper($username)."
".$lang_track.": ".strtoupper($trackname). 123 | "
". 124 | "
". 125 | "
".$lang_time.": ".$dateoccured."
". 126 | (($speed)?"".$lang_speed.": ".round($speed*3.6,2*$factor_kmh)." ".$unit_kmh."
":""). 127 | (($altitude != null)?"".$lang_altitude.": ".round($altitude*$factor_m)." ".$unit_m."
":""). 128 | "".$lang_ttime.": ".toHMS($totalSeconds)."
". 129 | "".$lang_aspeed.": ".(($totalSeconds!=0)?round($totalMeters/$totalSeconds*3.6*$factor_kmh,2):0)." ".$unit_kmh."
". 130 | "".$lang_tdistance.": ".round($totalMeters/1000*$factor_km,2)." ".$unit_km."
"."
". 131 | "
".$lang_point." ".$i." ".$lang_of." ".($query->num_rows-1)."
". 132 | "
"; 133 | $xml->startElement("description"); 134 | $xml->writeCData($description); 135 | $xml->endElement(); 136 | $xml->writeElement("styleUrl", $style); 137 | $xml->startElement("Point"); 138 | $coordinate[$i] = $longitude.",".$latitude.(($altitude) ? ",".$altitude : ""); 139 | $xml->writeElement("coordinates", $coordinate[$i]); 140 | $xml->endElement(); 141 | $xml->endElement(); 142 | $style = "#grayStyle"; // other elements 143 | } 144 | $coordinates = implode("\n",$coordinate); 145 | $xml->startElement("Placemark"); 146 | $xml->writeElement("styleUrl", "#lineStyle"); 147 | $xml->startElement("LineString"); 148 | $xml->writeElement("coordinates", $coordinates); 149 | $xml->endElement(); 150 | $xml->endElement(); 151 | 152 | 153 | $xml->endElement(); 154 | $xml->endElement(); 155 | $xml->endDocument(); 156 | $xml->flush(); 157 | 158 | break; 159 | 160 | case "gpx": 161 | header("Content-type: application/application/gpx+xm"); 162 | header("Content-Disposition: attachment; filename=\"track$trackid.gpx\""); 163 | $xml = new XMLWriter(); 164 | $xml->openURI("php://output"); 165 | $xml->startDocument("1.0"); 166 | $xml->startElement("gpx"); 167 | $xml->writeAttribute("xmlns", "http://www.topografix.com/GPX/1/1"); 168 | $xml->writeAttribute("xmlns:gpxdata", "http://www.cluetrust.com/XML/GPXDATA/1/0"); 169 | $xml->writeAttribute("creator", "phpTrackme"); 170 | $xml->writeAttribute("version", "1.1"); 171 | $xml->startElement("metadata"); 172 | $xml->writeElement("name", $trackname); 173 | $xml->writeElement("time", str_replace(" ","T",$dateoccured)); 174 | $xml->endElement(); 175 | $xml->startElement("trk"); 176 | $xml->writeElement("name", $trackname); 177 | $xml->startElement("trkseg"); 178 | $i = 0; 179 | $totalMeters = 0; 180 | $totalSeconds = 0; 181 | while ($query->fetch()) { 182 | $distance = (isset($prev_latitude))?haversine_distance($prev_latitude,$prev_longitude,$latitude,$longitude):0; 183 | $prev_latitude = $latitude; 184 | $prev_longitude = $longitude; 185 | $seconds = (isset($prev_dateoccured))?(strtotime($dateoccured)-strtotime($prev_dateoccured)):0; 186 | $prev_dateoccured = $dateoccured; 187 | $totalMeters += $distance; 188 | $totalSeconds += $seconds; 189 | $xml->startElement("trkpt"); 190 | $xml->writeAttribute("lat", $latitude); 191 | $xml->writeAttribute("lon", $longitude); 192 | if($altitude) { $xml->writeElement("ele", $altitude); } 193 | $xml->writeElement("time", str_replace(" ","T",$dateoccured)); 194 | $xml->writeElement("name", ++$i); 195 | $xml->startElement("desc"); 196 | $description = 197 | $lang_user.": ".strtoupper($username)." ".$lang_track.": ".strtoupper($trackname). 198 | " ".$lang_time.": ".$dateoccured. 199 | (($speed)?" ".$lang_speed.": ".round($speed*3.6,2*$factor_kmh)." ".$unit_kmh:""). 200 | (($altitude != null)?" ".$lang_altitude.": ".round($altitude*$factor_m)." ".$unit_m:""). 201 | " ".$lang_ttime.": ".toHMS($totalSeconds)."". 202 | " ".$lang_aspeed.": ".(($totalSeconds!=0)?round($totalMeters/$totalSeconds*3.6*$factor_kmh,2):0)." ".$unit_kmh. 203 | " ".$lang_tdistance.": ".round($totalMeters/1000*$factor_km,2)." ".$unit_km. 204 | " ".$lang_point." ".$i." ".$lang_of." ".($query->num_rows-1); 205 | $xml->writeCData($description); 206 | $xml->endElement(); 207 | $xml->endElement(); 208 | } 209 | $xml->endElement(); 210 | $xml->endElement(); 211 | $xml->endElement(); 212 | $xml->endDocument(); 213 | $xml->flush(); 214 | 215 | break; 216 | } 217 | $query->free_result(); 218 | $query->close(); 219 | } 220 | $mysqli->close(); 221 | ?> 222 | -------------------------------------------------------------------------------- /export.php: -------------------------------------------------------------------------------- 1 | 0"; 25 | exit(); 26 | ?> 27 | -------------------------------------------------------------------------------- /getpositions.php: -------------------------------------------------------------------------------- 1 | prepare("SELECT positions.ID,positions.Latitude,positions.Longitude,positions.Altitude,positions.Speed,positions.Angle,positions.DateOccurred,positions.Comments,users.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"); 40 | $query->bind_param('ii', $userid, $trackid); 41 | } 42 | else { 43 | // get data only for latest point 44 | $query = $mysqli->prepare("SELECT positions.ID,positions.Latitude,positions.Longitude,positions.Altitude,positions.Speed,positions.Angle,positions.DateOccurred,positions.Comments,users.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"); 45 | $query->bind_param('i', $userid); 46 | } 47 | $query->execute(); 48 | $query->bind_result($positionid,$latitude,$longitude,$altitude,$speed,$angle,$dateoccured,$comments,$username,$trackname,$trackid); 49 | 50 | header("Content-type: text/xml"); 51 | $xml = new XMLWriter(); 52 | $xml->openURI("php://output"); 53 | $xml->startDocument("1.0"); 54 | $xml->setIndent(true); 55 | $xml->startElement('root'); 56 | 57 | while ($query->fetch()) { 58 | $xml->startElement("position"); 59 | $xml->writeAttribute("id", $positionid); 60 | $xml->writeElement("latitude", $latitude); 61 | $xml->writeElement("longitude", $longitude); 62 | $xml->writeElement("altitude", ($altitude)?round($altitude):$altitude); 63 | $xml->writeElement("speed", $speed); 64 | $xml->writeElement("angle", $angle); 65 | $xml->writeElement("dateoccured", $dateoccured); 66 | $xml->writeElement("comments", $comments); 67 | $xml->writeElement("username", $username); 68 | $xml->writeElement("trackid", $trackid); 69 | $xml->writeElement("trackname", $trackname); 70 | $distance = (isset($prev_latitude))?haversine_distance($prev_latitude,$prev_longitude,$latitude,$longitude):0; 71 | $prev_latitude = $latitude; 72 | $prev_longitude = $longitude; 73 | $xml->writeElement("distance", round($distance)); 74 | $seconds = (isset($prev_dateoccured))?(strtotime($dateoccured)-strtotime($prev_dateoccured)):0; 75 | $prev_dateoccured = $dateoccured; 76 | $xml->writeElement("seconds", $seconds); 77 | $xml->endElement(); 78 | } 79 | 80 | $xml->endElement(); 81 | $xml->endDocument(); 82 | $xml->flush(); 83 | 84 | $query->free_result(); 85 | } 86 | 87 | $mysqli->close(); 88 | ?> 89 | -------------------------------------------------------------------------------- /gettrips.php: -------------------------------------------------------------------------------- 1 | prepare("SELECT ID,Name FROM trips WHERE FK_Users_ID=? ORDER BY ID DESC"); 26 | $query->bind_param('i', $userid); 27 | $query->execute(); 28 | $query->bind_result($trackid,$trackname); 29 | 30 | header("Content-type: text/xml"); 31 | $xml = new XMLWriter(); 32 | $xml->openURI("php://output"); 33 | $xml->startDocument("1.0"); 34 | $xml->setIndent(true); 35 | $xml->startElement('root'); 36 | 37 | while ($query->fetch()) { 38 | $xml->startElement("trip"); 39 | $xml->writeElement("trackid", $trackid); 40 | $xml->writeElement("trackname", $trackname); 41 | $xml->endElement(); 42 | } 43 | 44 | $xml->endElement(); 45 | $xml->endDocument(); 46 | $xml->flush(); 47 | 48 | $query->free_result(); 49 | } 50 | 51 | $mysqli->close(); 52 | ?> 53 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | query($query); 27 | $row = $result->fetch_assoc(); 28 | $user = $row["username"]; 29 | 30 | // users 31 | $user_form = ''.$lang_user.'
'.$user.' ('.$lang_logout.')'; 32 | } 33 | else { 34 | // free access or admin user 35 | // prepare user select form 36 | if ($admin) { 37 | $user = $admin_user; 38 | } 39 | $user_form = ' 40 | '.$lang_user.' '; 41 | if ($auth) { 42 | $user_form .= ' '.$user.' ('.$lang_logout.')'; 43 | } 44 | $user_form .= ' 45 |
46 |
47 | 65 |
66 | '; 67 | } 68 | 69 | // prepare track select form 70 | $track_form = ' 71 | '.$lang_track.'
72 |
73 | 92 | '.$lang_latest.'
93 |
94 | '; 95 | // map api select form 96 | $api_form = ' 97 | '.$lang_api.'
98 |
99 | 103 |
104 | '; 105 | 106 | // language select form 107 | $lang_form = ' 108 | '.$lang_language.'
109 |
110 | 115 |
116 | '; 117 | // units select form 118 | $units_form = ' 119 | '.$lang_units.'
120 |
121 | 125 |
126 | '; 127 | 128 | print 129 | ' 130 | 131 | 132 | '.$lang_title.' 133 | 134 | 135 | 136 | 163 | 164 | '; 165 | if ($mapapi == "gmaps") { 166 | print 167 | ' 168 | 169 | '; 170 | } 171 | else { 172 | print 173 | ' 174 | 175 | '; 176 | } 177 | print ' 178 | 179 | 182 | 183 | 184 | 185 | 217 |
218 |
219 |
220 |
221 | 222 |
223 |
224 | 225 | '; 226 | $mysqli->close(); 227 | ?> 228 | -------------------------------------------------------------------------------- /lang.php: -------------------------------------------------------------------------------- 1 | 163 | -------------------------------------------------------------------------------- /logout.php: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /main.css: -------------------------------------------------------------------------------- 1 | /* phpTrackme 2 | * 3 | * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net) 4 | * 5 | * This is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU Library General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | */ 19 | html { 20 | height: 100%; 21 | } 22 | body { 23 | height: 100%; 24 | margin: 0; 25 | padding: 0; 26 | background-color: #666; 27 | } 28 | a { 29 | color: #bce; 30 | text-decoration: none; 31 | } 32 | :link, :visited { 33 | color: #bce; 34 | } 35 | select { 36 | width: 150px; 37 | /*font-size: 0.6em;*/ 38 | font-weight: normal; 39 | padding-top: 0.2em; 40 | } 41 | #menu input, 42 | #login input { 43 | width: 150px; 44 | text-align: center; 45 | border: 1px solid black; 46 | } 47 | #menu input[type = "submit"], 48 | #login input[type = "submit"] { 49 | background-color: black; 50 | color: white; 51 | border: 1px solid white; 52 | } 53 | #menu input[type = "checkbox"] { 54 | width: auto; 55 | } 56 | #main { 57 | height: 100%; 58 | margin-right: 165px; 59 | } 60 | #map-canvas { 61 | height: 100%; 62 | } 63 | #menu { 64 | font-family: Verdana, sans-serif; 65 | font-size: 0.6em; 66 | font-weight: bold; 67 | color: white; 68 | float: right; 69 | width: 165px; 70 | height: 100%; 71 | background-color: #666; 72 | overflow: hidden; 73 | } 74 | #menu-content { 75 | padding: 10px; 76 | } 77 | #footer { 78 | position: fixed; 79 | width: 165px; 80 | bottom:0; 81 | padding: 10px; 82 | background-color:rgba(102, 102, 102, 0.9); 83 | color: lightgray; 84 | } 85 | #menu-close { 86 | background-color: #666; 87 | opacity: 0.9; 88 | position: absolute; 89 | top: 55px; 90 | right: 165px; 91 | z-index: 1900; 92 | width: 18px; 93 | height: 20px; 94 | line-height: 18px; 95 | text-align: right; 96 | font-size: 18px; 97 | font-weight: bolder; 98 | border-radius: 11px 0 0 11px; 99 | cursor: pointer; 100 | } 101 | 102 | #user, #trip, #summary, #export, #other, #units { 103 | padding-bottom: 10px; 104 | } 105 | #login { 106 | font-family: Verdana, sans-serif; 107 | position: relative; 108 | top: 10%; 109 | background-color: #444; 110 | width: 30%; 111 | min-width: 200px; 112 | margin: auto; 113 | padding: 30px; 114 | font-size: 0.8em; 115 | text-align: center; 116 | color: white; 117 | } 118 | #title { 119 | font-size: 1.3em; 120 | padding-bottom: 0.5em; 121 | padding-top: 0.6em; 122 | } 123 | #subtitle { 124 | padding-bottom: 2em; 125 | } 126 | #error { 127 | padding-top: 1.2em; 128 | color: yellow; 129 | } 130 | #popup { 131 | width:370px; 132 | min-height:130px; 133 | } 134 | #popup * { 135 | font-family: Roboto, Verdana, sans-serif; 136 | font-size: 12px; 137 | } 138 | #pheader { 139 | font-weight: bolder; 140 | padding-bottom: 5px; 141 | border-bottom: 1px solid gray; 142 | } 143 | #pcomments { 144 | clear: both; 145 | color: #903; 146 | } 147 | #pleft,#pright { 148 | float:left; 149 | padding-top: 5px; 150 | } 151 | #pleft { 152 | padding-right: 20px; 153 | } 154 | #pfooter { 155 | clear: both; 156 | font-size: smaller; 157 | padding-top: 20px; 158 | } 159 | #bottom { 160 | display: none; 161 | position: absolute; 162 | z-index: 10000; 163 | } 164 | #chart { 165 | position: fixed; 166 | bottom: 0; left:0; right: 0; 167 | height: 200px; 168 | margin-right: 165px; 169 | background-color: white; 170 | opacity: 0.8; 171 | } 172 | #close { 173 | position: fixed; 174 | bottom: 175px; 175 | right: 175px; 176 | z-index: 10001; 177 | font-family: Verdana, sans-serif; 178 | font-size: 0.8em; 179 | } 180 | 181 | #close a, #close:link, #close:visited { 182 | color: #5070af; 183 | } 184 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | /* phpTrackme 2 | * 3 | * Copyright(C) 2013 Bartek Fabiszewski (www.fabiszewski.net) 4 | * 5 | * This is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU Library General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Library General Public 16 | * License along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | */ 19 | 20 | // general stuff 21 | if (units=='imperial') { 22 | factor_kmh = 0.62; //to mph 23 | unit_kmh = 'mph'; 24 | factor_m = 3.28; // to feet 25 | unit_m = 'ft'; 26 | factor_km = 0.62; // to miles 27 | unit_km = 'mi'; 28 | } 29 | else { 30 | factor_kmh = 1; 31 | unit_kmh = 'km/h'; 32 | factor_m = 1; 33 | unit_m = 'm'; 34 | factor_km = 1; 35 | unit_km = 'km'; 36 | } 37 | var latest = 0; 38 | var latestTime = 0; 39 | var live = 0; 40 | var chart; 41 | var altitudes = new Array(); 42 | var altTimeout; 43 | function displayChart() { 44 | if (chart) { google.visualization.events.removeAllListeners(chart); } 45 | var data = new google.visualization.DataTable(); 46 | data.addColumn('number', 'id'); 47 | data.addColumn('number', 'altitude'); 48 | var altLen = altitudes.length; 49 | for (var i=0; i0) { 124 | clearMap(); 125 | displayTrack(xml,update); 126 | } 127 | xhr = null; 128 | } 129 | } 130 | xhr.open('GET','getpositions.php?trackid='+trackid+'&userid='+userid,true); 131 | xhr.send(); 132 | } 133 | 134 | function parsePosition(p) { 135 | // read data 136 | var latitude = getNode(p,'latitude'); 137 | var longitude = getNode(p,'longitude'); 138 | var altitude = getNode(p,'altitude'); // may be null 139 | if (altitude != null) { altitude = parseInt(altitude); } 140 | var speed = getNode(p,'speed'); // may be null 141 | if (speed != null) { speed = parseInt(speed); } 142 | var angle = getNode(p,'angle'); // may be null 143 | if (angle != null) { angle = parseInt(angle); } 144 | var comments = getNode(p,'comments'); // may be null 145 | var username = getNode(p,'username'); 146 | var trackname = getNode(p,'trackname'); 147 | var tid = getNode(p,'trackid'); 148 | var dateoccured = getNode(p,'dateoccured'); 149 | var distance = parseInt(getNode(p,'distance')); 150 | var seconds = parseInt(getNode(p,'seconds')); 151 | return { 152 | 'latitude': latitude, 153 | 'longitude': longitude, 154 | 'altitude': altitude, 155 | 'speed': speed, 156 | 'angle': angle, 157 | 'comments': comments, 158 | 'username': username, 159 | 'trackname': trackname, 160 | 'tid': tid, 161 | 'dateoccured': dateoccured, 162 | 'distance': distance, 163 | 'seconds': seconds 164 | }; 165 | } 166 | 167 | function load(type,userid,trackid) { 168 | var url = 'download.php?type='+type+'&userid='+userid+'&trackid='+trackid; 169 | window.location.assign(url); 170 | } 171 | 172 | function updateSummary(l,d,s) { 173 | var t = document.getElementById('summary'); 174 | if (latest==0){ 175 | t.innerHTML = ''+lang_summary+'
'+ 176 | lang_tdistance+': '+(d.toKm()*factor_km).toFixed(2)+' '+unit_km+'
'+ 177 | lang_ttime+': '+s.toHMS(); 178 | } 179 | else { 180 | t.innerHTML = ''+lang_latest+':
'+l; 181 | } 182 | } 183 | 184 | function getNode(p,name) { 185 | return ((p.getElementsByTagName(name)[0].childNodes[0]) ? p.getElementsByTagName(name)[0].childNodes[0].nodeValue : null); 186 | } 187 | 188 | 189 | // seconds to (d) H:M:S 190 | Number.prototype.toHMS = function(){ 191 | var s = this; 192 | var d = Math.floor(s / 86400); 193 | var h = Math.floor((s % 86400) / 3600); 194 | var m = Math.floor(((s % 86400) % 3600) / 60); 195 | s = ((s % 86400) % 3600) % 60; 196 | 197 | return ((d>0)?(d + ' d '):'') + (('00'+h).slice(-2)) + ':' + (('00'+m).slice(-2)) + ':' + (('00'+s).slice(-2)) + ''; 198 | } 199 | // meters to km 200 | Number.prototype.toKm = function() { 201 | return Math.round(this/10)/100; 202 | } 203 | // m/s to km/h 204 | Number.prototype.toKmH = function() { 205 | return Math.round(this*3600/10)/100; 206 | } 207 | 208 | // negate value 209 | function toggleLatest() { 210 | if (latest==0) { 211 | latest = 1; 212 | loadTrack(userid,0,1); 213 | } 214 | else { 215 | latest = 0; 216 | loadTrack(userid,trackid,1); 217 | } 218 | } 219 | 220 | function setTrack(t) { 221 | document.getElementsByName('track')[0].value = t; 222 | } 223 | 224 | function selectTrack(f) { 225 | trackid=f.options[f.selectedIndex].value; 226 | document.getElementById('latest').checked = false; 227 | if (latest==1) { toggleLatest(); } 228 | loadTrack(userid,trackid,1); 229 | } 230 | 231 | function selectUser(f) { 232 | userid=f.options[f.selectedIndex].value; 233 | if (f.options[0].disabled==false) { 234 | f.options[0].disabled = true; 235 | } 236 | document.getElementById('latest').checked = false; 237 | if (latest==1) { toggleLatest(); } 238 | getTrips(userid); 239 | } 240 | 241 | function getTrips(userid) { 242 | var xhr = getXHR(); 243 | xhr.onreadystatechange = function() { 244 | if (xhr.readyState==4 && xhr.status==200) { 245 | var xml = xhr.responseXML; 246 | var trackSelect = document.getElementsByName('track')[0]; 247 | clearOptions(trackSelect); 248 | var trips = xml.getElementsByTagName('trip'); 249 | if (trips.length>0) { 250 | fillOptions(xml); 251 | } else { 252 | clearMap(); 253 | } 254 | xhr = null; 255 | } 256 | } 257 | xhr.open('GET','gettrips.php?userid='+userid,true); 258 | xhr.send(); 259 | } 260 | 261 | function fillOptions(xml) { 262 | var trackSelect = document.getElementsByName('track')[0]; 263 | var trips = xml.getElementsByTagName('trip'); 264 | var trpLen = trips.length; 265 | for (var i=0; i5000) { loadTime = 0; alert('Sorry, can\'t load '+api+' API'); return; } 334 | if (loadedAPI!==api) { 335 | setTimeout(function() { loadTime += 50; waitAndLoad(api,url); }, 50); 336 | return; 337 | } 338 | if(!isScriptLoaded(url[1])){ 339 | addScript(url[1]); 340 | } 341 | loadTime = 0; 342 | waitAndInit(api); 343 | } 344 | 345 | function waitAndInit(api) { 346 | // wait till main api loads 347 | if (loadTime>10000) { loadTime = 0; alert('Sorry, can\'t load '+api+' API'); return; } 348 | try { 349 | init(); 350 | } 351 | catch(e) { 352 | setTimeout(function() { loadTime += 50; waitAndInit(api); }, 50); 353 | return; 354 | } 355 | loadTime = 0; 356 | zoomToBounds(savedBounds); 357 | loadTrack(userid,trackid,0); 358 | // save current api as default 359 | setCookie('api',api,30); 360 | } 361 | 362 | function addScript(url) { 363 | var tag = document.createElement('script'); 364 | tag.setAttribute('type','text/javascript'); 365 | tag.setAttribute('src', url); 366 | if (typeof tag!='undefined') { 367 | document.getElementsByTagName('head')[0].appendChild(tag); 368 | } 369 | } 370 | 371 | function isScriptLoaded(url) { 372 | scripts = document.getElementsByTagName('script'); 373 | for (var i = scripts.length; i--;) { 374 | // check if url matches src 375 | var scriptUrl = scripts[i].src.replace(/https?:/,''); 376 | if (scriptUrl != '' && url.indexOf(scriptUrl) !== -1) return true; 377 | } 378 | return false; 379 | } 380 | 381 | function setCookie(name,value,days) { 382 | if (days) { 383 | var date = new Date(); 384 | date.setTime(date.getTime()+(days*24*60*60*1000)); 385 | var expires = '; expires='+date.toGMTString(); 386 | } 387 | else { 388 | var expires = ''; 389 | } 390 | document.cookie = 'phpTrackme_'+name+'='+value+expires+'; path=/'; 391 | } 392 | 393 | function setLang(lang) { 394 | setCookie('lang',lang,30); 395 | location.reload(); 396 | } 397 | 398 | function setUnits(unit) { 399 | units = unit; 400 | setCookie('units',unit,30); 401 | location.reload(); 402 | } 403 | -------------------------------------------------------------------------------- /requests.php: -------------------------------------------------------------------------------- 1 | connect_errno) { 42 | //Result:4 Unable to connect database. 43 | quit(4); 44 | } 45 | 46 | if ((!$user) || (!$pass)){ 47 | //Result:3 User or password not specified. 48 | quit(3); 49 | } 50 | 51 | $query = $mysqli->prepare("SELECT ID,username,password FROM users WHERE username=? LIMIT 1"); 52 | $query->bind_param('s', $user); 53 | $query->execute(); 54 | $query->store_result(); 55 | $query->bind_result($userid, $rec_user, $rec_pass); 56 | $query->fetch(); 57 | $num = $query->num_rows; 58 | $query->free_result(); 59 | $query->close(); 60 | if ($num) { 61 | if (($user==$rec_user) && ($pass!=$rec_pass)) { 62 | //Result:1 User correct, invalid password. 63 | quit(1); 64 | } 65 | } 66 | else { 67 | if ($allow_registration) { 68 | // User unknown, let's create it 69 | $query = $mysqli->prepare("INSERT INTO users (username,password) VALUES (?,?)"); 70 | $query->bind_param('ss', $user, $pass); 71 | $query->execute(); 72 | $userid = $mysqli->insert_id; 73 | $query->close(); 74 | if (!$userid) { 75 | //Result:2 User did not exist but after being created couldn't be found. 76 | // Or rather something went wrong while updating database 77 | quit(2); 78 | } 79 | } 80 | else { 81 | // User unknown, we don't allow autoregistration 82 | // Let's use this one: 83 | //Result:1 User correct, invalid password. 84 | quit(1); 85 | } 86 | } 87 | 88 | switch($action) { 89 | // action: noop 90 | case "noop": 91 | // test 92 | quit(0); 93 | break; 94 | 95 | // action: deletetrip 96 | case "deletetrip": 97 | if ($tripname) { 98 | $sql = "DELETE FROM positions LEFT JOIN trips ON positions.FK_Trips_ID=trips.ID " 99 | ."WHERE positions.FK_Users_ID=? AND trips.Name=?"; 100 | $query = $mysqli->prepare($sql); 101 | if ($query) { 102 | $query->bind_param('is', $userid, $tripname); 103 | $query->execute(); 104 | $query->close(); 105 | } 106 | $sql = "DELETE FROM trips WHERE FK_Users_ID=? AND Name=?"; 107 | $query = $mysqli->prepare($sql); 108 | $query->bind_param('is', $userid, $tripname); 109 | $query->execute(); 110 | $rows = $mysqli->affected_rows; 111 | $query->close(); 112 | if ($rows) { 113 | quit(0); 114 | } 115 | else { 116 | //Result:7 Trip not found 117 | quit(7); 118 | } 119 | } 120 | else { 121 | //Result:6 Trip not specified. 122 | quit(6); 123 | } 124 | break; 125 | 126 | // action: addtrip 127 | case "addtrip": 128 | if ($tripname) { 129 | $sql = "INSERT INTO trips (FK_Users_ID,Name) VALUES (?,?)"; 130 | $query = $mysqli->prepare($sql); 131 | $query->bind_param('is', $userid, $tripname); 132 | $query->execute(); 133 | $query->close(); 134 | } 135 | else { 136 | //Result:6 Trip not specified. 137 | quit(6); 138 | } 139 | break; 140 | 141 | // action: gettriplist 142 | case "gettriplist": 143 | $sql = "SELECT a1.Name,(SELECT MIN(a2.DateOccurred) FROM positions a2 " 144 | ."WHERE a2.FK_Trips_ID=a1.ID) AS startdate " 145 | ."FROM trips a1 WHERE a1.FK_Users_ID=? ORDER BY Name"; 146 | $query = $mysqli->prepare($sql); 147 | $query->bind_param('i', $userid); 148 | $query->execute(); 149 | $query->store_result(); 150 | $query->bind_result($tripname,$startdate); 151 | $num = $query->num_rows; 152 | $triplist = array(); 153 | if ($num) { 154 | while ($query->fetch()) { 155 | $triplist[] = $tripname."|".$startdate; 156 | } 157 | } 158 | $query->free_result(); 159 | $query->close(); 160 | $param = implode("\n",$triplist); 161 | quit(0,$param); 162 | break; 163 | 164 | // action: upload 165 | case "upload": 166 | $lat = isset($_REQUEST["lat"]) ? $_REQUEST["lat"] : NULL; 167 | $long = isset($_REQUEST["long"]) ? $_REQUEST["long"] : NULL; 168 | // If the client uses Backitude then convert the date into handled format 169 | $dateoccurred = isset($_REQUEST["do"]) ? $_REQUEST["do"] : NULL; 170 | $altitude = isset($_REQUEST["alt"]) ? $_REQUEST["alt"] : NULL; 171 | $angle = isset($_REQUEST["ang"]) ? $_REQUEST["ang"] : NULL; 172 | $speed = isset($_REQUEST["sp"]) ? $_REQUEST["sp"] : NULL; 173 | $iconname = isset($_REQUEST["iconname"]) ? $_REQUEST["iconname"] : NULL; 174 | $comments = isset($_REQUEST["comments"]) ? $_REQUEST["comments"] : NULL; 175 | $imageurl = isset($_REQUEST["imageurl"]) ? $_REQUEST["imageurl"] : NULL; 176 | $cellid = isset($_REQUEST["cid"]) ? $_REQUEST["cid"] : NULL; 177 | $signalstrength = isset($_REQUEST["ss"]) ? $_REQUEST["ss"] : NULL; 178 | $signalstrengthmax = isset($_REQUEST["ssmax"]) ? $_REQUEST["ssmax"] : NULL; 179 | $signalstrengthmin = isset($_REQUEST["ssmin"]) ? $_REQUEST["ssmin"] : NULL; 180 | $batterystatus = isset($_REQUEST["bs"]) ? $_REQUEST["bs"] : NULL; 181 | $uploadss = isset($_REQUEST["upss"]) ? $_REQUEST["upss"] : NULL; // FIXME is it needed? 182 | $iconid = NULL; 183 | if ($iconname) { 184 | $sql = "SELECT ID FROM icons WHERE Name=? LIMIT 1"; 185 | $query = $mysqli->prepare($sql); 186 | $query->bind_param('s', $iconname); 187 | $query->execute(); 188 | $query->store_result(); 189 | $query->bind_result($id); 190 | $query->fetch(); 191 | $num = $query->num_rows; 192 | $query->free_result(); 193 | $query->close(); 194 | if ($num) { 195 | $iconid = $id; 196 | } 197 | } 198 | $tripid = NULL; // FIXME: not sure what trips with null id are 199 | if ($tripname) { 200 | // get tripid 201 | $query = $mysqli->prepare("SELECT ID FROM trips WHERE FK_Users_ID=? AND Name=? LIMIT 1"); 202 | $query->bind_param('is', $userid, $tripname); 203 | $query->execute(); 204 | $query->store_result(); 205 | $query->bind_result($tripid); 206 | $query->fetch(); 207 | $num = $query->num_rows; 208 | $query->free_result(); 209 | $query->close(); 210 | if (!$num) { 211 | // create trip 212 | $query = $mysqli->prepare("INSERT INTO trips (FK_Users_ID,Name) VALUES (?,?)"); 213 | $query->bind_param('is', $userid, $tripname); 214 | $query->execute(); 215 | $tripid = $mysqli->insert_id; 216 | $query->close(); 217 | if (!$tripid) { 218 | //Result:6 Trip didn't exist and system was unable to create it. 219 | quit(6); 220 | } 221 | } 222 | } 223 | if ($requireddb == 'backitude') { 224 | $sql = "INSERT INTO positions " 225 | ."(FK_Users_ID,FK_Trips_ID,Latitude,Longitude,DateOccurred,FK_Icons_ID," 226 | ."Speed,Altitude,Comments,ImageURL,Angle,SignalStrength,SignalStrengthMax," 227 | ."SignalStrengthMin,BatteryStatus) VALUES (?,?,?,?,FROM_UNIXTIME(?),?,?,?,?,?,?,?,?,?,?)"; 228 | } else { 229 | $sql = "INSERT INTO positions " 230 | ."(FK_Users_ID,FK_Trips_ID,Latitude,Longitude,DateOccurred,FK_Icons_ID," 231 | ."Speed,Altitude,Comments,ImageURL,Angle,SignalStrength,SignalStrengthMax," 232 | ."SignalStrengthMin,BatteryStatus) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; 233 | } 234 | 235 | $query = $mysqli->prepare($sql); 236 | $query->bind_param('iiddsiddssdiiii', 237 | $userid,$tripid,$lat,$long,$dateoccurred,$iconid, 238 | $speed,$altitude,$comments,$imageurl,$angle,$signalstrength,$signalstrengthmax, 239 | $signalstrengthmin,$batterystatus); 240 | $query->execute(); 241 | $query->close(); 242 | if ($mysqli->errno) { 243 | //Result:7|SQLERROR Insert statement failed. 244 | quit(7,$mysqli->error); 245 | } 246 | //FIXME Are cellids used in Android client? 247 | $upcellext = isset($_REQUEST["upcellext"]) ? $_REQUEST["upcellext"] : NULL; 248 | if ($upcellext==1 && $cellid) { 249 | $sql = "INSERT INTO cellids (CellID,Latitude,Longitude,SignalStrength,SignalStrengthMax,SignalStrengthMin) " 250 | ."VALUES (?,?,?,?,?,?)"; 251 | $query = $mysqli->prepare($sql); 252 | $query->bind_param('sddiii',$cellid,$lat,$long,$signalstrength,$signalstrengthmax,$signalstrengthmin); 253 | $query->execute(); 254 | $query->close(); 255 | if ($mysqli->errno) { 256 | //Result:7|SQLERROR Insert statement failed. 257 | quit(7,$mysqli->error); 258 | } 259 | } 260 | quit(0); 261 | break; 262 | 263 | // action: geticonlist 264 | // action: renametrip 265 | // action: findclosestbuddy 266 | // action: delete 267 | // action: sendemail 268 | // action: updateimageurl 269 | // action: findclosestpositionbytime 270 | // action: findclosestpositionbyposition 271 | // action: gettripinfo 272 | // action: gettriphighlights 273 | } 274 | 275 | function quit($errno,$param=""){ 276 | print "Result:".$errno.(($param)?"|$param":""); 277 | exit(); 278 | } 279 | 280 | $mysqli->close(); 281 | ?> 282 | -------------------------------------------------------------------------------- /trackme.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- Database layout inherited from TrackMe 3 | -- Some tables/columns are not used by the viewer at the moment. 4 | -- Kept for compatibility with old data. 5 | -- 6 | 7 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 8 | SET time_zone = "+00:00"; 9 | CREATE DATABASE IF NOT EXISTS `trackme` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci; 10 | USE `trackme`; 11 | 12 | CREATE TABLE IF NOT EXISTS `cellids` ( 13 | `ID` int(11) NOT NULL auto_increment, 14 | `CellID` varchar(255) NOT NULL, 15 | `Latitude` double NOT NULL, 16 | `Longitude` double NOT NULL, 17 | `DateAdded` timestamp NOT NULL default CURRENT_TIMESTAMP, 18 | `SignalStrength` int(11) default NULL, 19 | `SignalStrengthMax` int(11) default NULL, 20 | `SignalStrengthMin` int(11) default NULL, 21 | PRIMARY KEY (`ID`), 22 | KEY `Index_CellID` (`CellID`) 23 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 24 | 25 | CREATE TABLE IF NOT EXISTS `icons` ( 26 | `ID` int(11) NOT NULL auto_increment, 27 | `Name` varchar(255) NOT NULL, 28 | `URL` varchar(512) NOT NULL, 29 | PRIMARY KEY (`ID`) 30 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 31 | 32 | CREATE TABLE IF NOT EXISTS `positions` ( 33 | `ID` int(11) NOT NULL auto_increment, 34 | `FK_Users_ID` int(11) NOT NULL, 35 | `FK_Trips_ID` int(11) default NULL, 36 | `FK_Icons_ID` int(11) default NULL, 37 | `Latitude` double NOT NULL, 38 | `Longitude` double NOT NULL, 39 | `Altitude` double default '0', 40 | `Speed` double default '0', 41 | `Angle` double default NULL, 42 | `DateAdded` timestamp NOT NULL default CURRENT_TIMESTAMP, 43 | `DateOccurred` timestamp NULL default '0000-00-00 00:00:00', 44 | `Comments` varchar(255) default NULL, 45 | `ImageURL` varchar(255) default NULL, 46 | `SignalStrength` int(11) default NULL, 47 | `SignalStrengthMax` int(11) default NULL, 48 | `SignalStrengthMin` int(11) default NULL, 49 | `BatteryStatus` tinyint(4) default NULL, 50 | PRIMARY KEY (`ID`), 51 | KEY `Index_FK_Trips_ID` (`FK_Trips_ID`), 52 | KEY `Index_FK_Users_ID` (`FK_Users_ID`) 53 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 54 | 55 | CREATE TABLE IF NOT EXISTS `trips` ( 56 | `ID` int(11) NOT NULL auto_increment, 57 | `FK_Users_ID` int(11) NOT NULL, 58 | `Name` varchar(255) NOT NULL, 59 | `Comments` varchar(1024) default NULL, 60 | PRIMARY KEY (`ID`), 61 | UNIQUE KEY `Index_FK_Users_ID_Name` (`FK_Users_ID`,`Name`) 62 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 63 | 64 | CREATE TABLE IF NOT EXISTS `users` ( 65 | `ID` int(11) NOT NULL auto_increment, 66 | `username` varchar(15) NOT NULL, 67 | `password` varchar(50) NOT NULL default '', 68 | PRIMARY KEY (`ID`), 69 | UNIQUE KEY `Index_username` (`username`) 70 | ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 71 | 72 | INSERT INTO `icons` VALUES (1, 'Snack', 'http://maps.google.com/mapfiles/ms/micons/snack_bar.png'); 73 | INSERT INTO `icons` VALUES (2, 'Hiking', 'http://maps.google.com/mapfiles/ms/micons/hiker.png'); 74 | INSERT INTO `icons` VALUES (3, 'Lodging', 'http://maps.google.com/mapfiles/ms/micons/lodging.png'); 75 | INSERT INTO `icons` VALUES (4, 'Restaurant', 'http://maps.google.com/mapfiles/ms/micons/restaurant.png'); 76 | INSERT INTO `icons` VALUES (5, 'POI', 'http://maps.google.com/mapfiles/ms/micons/POI.png'); 77 | INSERT INTO `icons` VALUES (6, 'Arts', 'http://maps.google.com/mapfiles/ms/micons/arts.png'); 78 | INSERT INTO `icons` VALUES (7, 'Bar', 'http://maps.google.com/mapfiles/ms/micons/bar.png'); 79 | INSERT INTO `icons` VALUES (8, 'Blue-dot', 'http://maps.google.com/mapfiles/ms/micons/blue-dot.png'); 80 | INSERT INTO `icons` VALUES (9, 'Bus', 'http://maps.google.com/mapfiles/ms/micons/bus.png'); 81 | INSERT INTO `icons` VALUES (10, 'Taxi', 'http://maps.google.com/mapfiles/ms/micons/cabs.png'); 82 | INSERT INTO `icons` VALUES (11, 'Camera', 'http://maps.google.com/mapfiles/ms/micons/camera.png'); 83 | INSERT INTO `icons` VALUES (12, 'Camping', 'http://maps.google.com/mapfiles/ms/micons/campground.png'); 84 | INSERT INTO `icons` VALUES (13, 'Caution', 'http://maps.google.com/mapfiles/ms/micons/caution.png'); 85 | INSERT INTO `icons` VALUES (14, 'Coffee House', 'http://maps.google.com/mapfiles/ms/micons/coffeehouse.png'); 86 | INSERT INTO `icons` VALUES (15, 'Store', 'http://maps.google.com/mapfiles/ms/micons/convienancestore.png'); 87 | INSERT INTO `icons` VALUES (16, 'Cycling', 'http://maps.google.com/mapfiles/ms/micons/cycling.png'); 88 | INSERT INTO `icons` VALUES (17, 'Dollar', 'http://maps.google.com/mapfiles/ms/micons/dollar.png'); 89 | INSERT INTO `icons` VALUES (18, 'Drinking water', 'http://maps.google.com/mapfiles/ms/micons/drinking_water.png'); 90 | INSERT INTO `icons` VALUES (19, 'Electronics', 'http://maps.google.com/mapfiles/ms/micons/electronics.png'); 91 | INSERT INTO `icons` VALUES (20, 'Falling Rocks', 'http://maps.google.com/mapfiles/ms/micons/fallingrocks.png'); 92 | INSERT INTO `icons` VALUES (21, 'Ferry', 'http://maps.google.com/mapfiles/ms/micons/ferry.png'); 93 | INSERT INTO `icons` VALUES (22, 'Fire Dept.', 'http://maps.google.com/mapfiles/ms/micons/firedept.png'); 94 | INSERT INTO `icons` VALUES (23, 'Fishing', 'http://maps.google.com/mapfiles/ms/micons/fishing.png'); 95 | INSERT INTO `icons` VALUES (24, 'Flag', 'http://maps.google.com/mapfiles/ms/micons/flag.png'); 96 | INSERT INTO `icons` VALUES (25, 'Gas', 'http://maps.google.com/mapfiles/ms/micons/gas.png'); 97 | INSERT INTO `icons` VALUES (26, 'Grocery Store', 'http://maps.google.com/mapfiles/ms/micons/grocerystore.png'); 98 | INSERT INTO `icons` VALUES (27, 'Helicopter', 'http://maps.google.com/mapfiles/ms/micons/helicopter.png'); 99 | INSERT INTO `icons` VALUES (28, 'Horseback riding', 'http://maps.google.com/mapfiles/ms/micons/horsebackriding.png'); 100 | INSERT INTO `icons` VALUES (29, 'Hospital', 'http://maps.google.com/mapfiles/ms/micons/hospitals.png'); 101 | INSERT INTO `icons` VALUES (30, 'Hot springs', 'http://maps.google.com/mapfiles/ms/micons/hotsprings.png'); 102 | INSERT INTO `icons` VALUES (31, 'Info', 'http://maps.google.com/mapfiles/ms/micons/info.png'); 103 | INSERT INTO `icons` VALUES (32, 'Info 2', 'http://maps.google.com/mapfiles/ms/micons/info_circle.png'); 104 | INSERT INTO `icons` VALUES (33, 'Man', 'http://maps.google.com/mapfiles/ms/micons/man.png'); 105 | INSERT INTO `icons` VALUES (34, 'Marina', 'http://maps.google.com/mapfiles/ms/micons/marina.png'); 106 | INSERT INTO `icons` VALUES (35, 'Mechanic', 'http://maps.google.com/mapfiles/ms/micons/mechanic.png'); 107 | INSERT INTO `icons` VALUES (36, 'Motorcycling', 'http://maps.google.com/mapfiles/ms/micons/motorcycling.png'); 108 | INSERT INTO `icons` VALUES (37, 'Parking', 'http://maps.google.com/mapfiles/ms/micons/parkinglot.png'); 109 | INSERT INTO `icons` VALUES (38, 'Partly Cloudy', 'http://maps.google.com/mapfiles/ms/micons/partly_cloudy.png'); 110 | INSERT INTO `icons` VALUES (39, 'Phone', 'http://maps.google.com/mapfiles/ms/micons/phone.png'); 111 | INSERT INTO `icons` VALUES (40, 'Picnic', 'http://maps.google.com/mapfiles/ms/micons/picnic.png'); 112 | INSERT INTO `icons` VALUES (41, 'Plane', 'http://maps.google.com/mapfiles/ms/micons/plane.png'); 113 | INSERT INTO `icons` VALUES (42, 'Police', 'http://maps.google.com/mapfiles/ms/micons/police.png'); 114 | INSERT INTO `icons` VALUES (43, 'Post Office', 'http://maps.google.com/mapfiles/ms/micons/postoffice-us.png'); 115 | INSERT INTO `icons` VALUES (44, 'Question mark', 'http://maps.google.com/mapfiles/ms/micons/question.png'); 116 | INSERT INTO `icons` VALUES (45, 'Rail', 'http://maps.google.com/mapfiles/ms/micons/rail.png'); 117 | INSERT INTO `icons` VALUES (46, 'Rainy', 'http://maps.google.com/mapfiles/ms/micons/rainy.png'); 118 | INSERT INTO `icons` VALUES (47, 'Ranger Station', 'http://maps.google.com/mapfiles/ms/micons/rangerstation.png'); 119 | INSERT INTO `icons` VALUES (48, 'Recycle', 'http://maps.google.com/mapfiles/ms/micons/recycle.png'); 120 | INSERT INTO `icons` VALUES (49, 'Snow', 'http://maps.google.com/mapfiles/ms/micons/snowflake_simple.png'); 121 | INSERT INTO `icons` VALUES (50, 'Sport', 'http://maps.google.com/mapfiles/ms/micons/sportvenue.png'); 122 | INSERT INTO `icons` VALUES (51, 'Subway', 'http://maps.google.com/mapfiles/ms/micons/subway.png'); 123 | INSERT INTO `icons` VALUES (52, 'Sunny', 'http://maps.google.com/mapfiles/ms/micons/sunny.png'); 124 | INSERT INTO `icons` VALUES (53, 'Swimming', 'http://maps.google.com/mapfiles/ms/micons/swimming.png'); 125 | INSERT INTO `icons` VALUES (54, 'Toilets', 'http://maps.google.com/mapfiles/ms/micons/toilets.png'); 126 | INSERT INTO `icons` VALUES (55, 'Trail', 'http://maps.google.com/mapfiles/ms/micons/trail.png'); 127 | INSERT INTO `icons` VALUES (56, 'Tree', 'http://maps.google.com/mapfiles/ms/micons/tree.png'); 128 | INSERT INTO `icons` VALUES (57, 'Truck', 'http://maps.google.com/mapfiles/ms/micons/truck.png'); 129 | INSERT INTO `icons` VALUES (58, 'Volcano', 'http://maps.google.com/mapfiles/ms/micons/volcano.png'); 130 | INSERT INTO `icons` VALUES (59, 'Water', 'http://maps.google.com/mapfiles/ms/micons/water.png'); 131 | INSERT INTO `icons` VALUES (60, 'Waterfalls', 'http://maps.google.com/mapfiles/ms/micons/waterfalls.png'); 132 | INSERT INTO `icons` VALUES (61, 'Wheel Chair', 'http://maps.google.com/mapfiles/ms/micons/wheel_chair_accessible.png'); 133 | INSERT INTO `icons` VALUES (62, 'Woman', 'http://maps.google.com/mapfiles/ms/micons/woman.png'); 134 | INSERT INTO `icons` VALUES (63, 'Monster gate', 'http://img.gamespot.com/gamespot/shared/user/emblem_e3monster_s.jpg'); 135 | --------------------------------------------------------------------------------