Condividi tramite


Geolocalizzare un dispositivo e memorizzare coordinate su Webserver (it-IT)


Introduzione

In questo articolo vedremo come creare una semplice app di geolocalizzazione per Windows Phone, e come salvare le coordinate da essa acquisite su un Web server remoto, in modo da potervi poi accedere. Per la creazione dell'app utilizzeremo C#, mentre sul versante Web svilupperemo tramite PHP + MySQL, in modo da avere un sistema che possa essere eseguito su più sistemi.

Prerequisiti

Per utilizzare il codice presente nell'articolo, è necessario:

  • Windows 8.1
  • Visual Studio con Windows Phone 8.1 SDK
  • Un web server (anche locale) con Apache, supporto PHP abilitato e database MySQL (il pacchetto phpMyAdmin può essere utile). Alternativamente, la parte inerente il web server potrà essere redatta anche in ASP/ASP.NET.

La configurazione dei prerequisiti va oltre le finalità dell'articolo, e non verrà di conseguenza trattata in questa sede, assumendo che tutto sia preventivamente stato configurato. In caso si necessitasse di una rapida referenza sull'installazione di un web server Apache, corredato da PHP/Mysql, si può far riferimento al mio how-to sull'argomento, Quickly installing LAMP server on Debian or Ubuntu Linux

Analisi dello scenario

Nel pensare ad uno scenario dimostrativo utile a mostrare le potenzialità della geolocalizzazione, rimarremo il più semplici possibile: vi sono molti aspetti inerenti la sicurezza che non analizzeremo in questa sede, e di conseguenza ciò che si intende fornire qui è una panoramica generale, un punto di partenza dal quale sviluppare ulteriori soluzioni. Ciò che considereremo in questa sede parte da un concetto semplice: abbiamo un dispositivo (nel mio caso uno smartphone) con sensore GPS e possibilità di interfacciamento di rete, che dovrà trasmettere dati. Dall'altra parte vi sarà un programma in ambito web server, in attesa di ricevere tali dati e salvarli. Nel seguito dell'articolo, realizzeremo un'app C# capace di acquisire la posizione geografica del dispositivo che la esegue (in termini di latitudine/longitudine), e di inviare tali dati verso un URL specifico. Lato server, realizzeremo uno script PHP che possa captare tali dati attraverso il metodo GET, procedendo quindi al loro salvataggio in una tabella MySQL.

Setup del Database

Per prima cosa, dovremo creare una tabella adatta alla memorizzazione dei dati raccolti. Quanto segue è lo script T-SQL per la creazione della tabella, script che potrà essere eseguito in phpMyAdmin. Ho qui creato un nuovo database, di nome "geolog", nel quale creeremo la tabella "entries". In essa salveremo i dati che lo smartphone invierà, ovvero la latitudine/longitudine, il nome del device (nel caso volessimo tracciare più dispositivi) ed eventuali annotazioni dell'utente. I restanti campi (IdEntry e imeStamp) saranno compilati automaticamente dai vincoli di default sulle rispettive colonne: IdEntry è un campo auto-incrementante, mentre TimeStamp prenderà il suo valore dal timestamp occorrente durante l'operazione di INSERT dei dati.

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
 
CREATE TABLE  entries (
  IdEntry int(9) NOT NULL AUTO_INCREMENT,
  `TimeStamp` timestamp  NOT NULL  DEFAULT CURRENT_TIMESTAMP,
  Latitude decimal(12,8) NOT NULL DEFAULT  '0.00000000',
  Longitude decimal(12,8) NOT NULL DEFAULT  '0.00000000',
  Device varchar(50) NOT NULL DEFAULT  '',
  Annotation text NOT NULL,
  PRIMARY KEY  (IdEntry),
  KEY Idx_Device (Device),
  KEY Idx_Entry (IdEntry,`TimeStamp`)
) ENGINE=InnoDB  DEFAULT  CHARSET=utf8 AUTO_INCREMENT=1;

Ora, sulla nostra istanza MySQL, dovremmo poter vedere la nostra tabella vuota, e siamo quindi pronti alla stesura del codice PHP per ottenere la parte di funzionalità server: avere cioè uno script che possa ricevere dati dall'esterno, scriverli nella nostra tabella, ed un secondo script che possa effettuarne l'interrogazione. Iniziamo con la creazione di una prima pagina PHP di nome index.php.

Memorizzare i dati con PHP

Index.php dovrà eseguire un compito molto semplice: ricevendo tramite richiesta GET determinati parametri, dovrà leggere ciascuno di essi per eseguire poi un'operazione di INSERT sulla tabella "entries", in modo da memorizzare i valori passati. Di nuovo, si noti che non vengono qui implementate procedure particolari di sicurezza (escludendo i prepared statements, ovvero il corrispettivo PHP delle parametrized queries in ASP.NET): nel caso si desideri utilizzare il codice presentato in uno scenario reale, sarà necessario applicare criteri di sicurezza ben definiti.

Il codice è minimale e di facile intuizione: per prima cosa si apre una connessione verso il database, procedendo quindi alla lettura delle variabili GET, ed eseguendo quindi l'INSERT, al completamento del quale la connessione verrà chiusa. Per ora, è tutto ciò che ci serve.

01.<?php
02.   //-- Connecting to "geolog" database, on "localhost" server: replace <USER> and <PASSWORD> variables with the ones which corresponds to your MySQL installation
03.   $mysqli = new mysqli('localhost', '<USER>',  '<PASSWORD>',  'geolog');
04.   if ($mysqli->connect_errno) {
05.      echo "Failed to connect to MySQL: ("  . $mysqli->connect_errno . ") " .  $mysqli->connect_error;
06.      exit();
07.   }
08. 
09.   //-- Preparing parametrized INSERT
10.   if (!($stmt  = $mysqli->prepare("INSERT INTO entries(Latitude, Longitude, Device, Annotation) VALUES (?, ?, ?, ?)"))) {
11.       echo "Prepare failed: (" . $mysqli->errno . ") " .  $mysqli->error;
12.   }
13. 
14.   //-- Acquire GET parameters   
15.   $latitude   = $_GET['lt'];
16.   $longitude  = $_GET['ln'];
17.   $device     = $_GET['d'];
18.   $annotation = $_GET['n'];
19.    
20.   //-- Bind GET parameters to prepared statement's variables
21.   if (!$stmt->bind_param("ddss", $latitude,  $longitude,  $device, $annotation)) {
22.      echo "Binding parameters failed: ("  . $stmt->errno . ") " .  $stmt->error;
23.   }
24. 
25.   //-- Execute INSERT query
26.   if (!$stmt->execute()) {
27.       echo "Execute failed: (" . $stmt->errno . ") " .  $stmt->error;
28.   }   
29. 
30.   //-- Closing connection / cleanup
31.   $stmt->close();
32.   mysqli_close($mysqli);
33.?>

Ciò che significa nella pratica, è che aprendo un browser, e richiamando un URL avente una determinata formattazione, finiremo per scrivere dati nel nostro database. Vediamo un esempio, assumendo che il nostro webserver stia girando su localhost.

La sottodirectory /test che vedete nella barra degli indirizzi è una directory virtuale creata su Apache per ospitare l'applicazione web: può essere una qualsiasi directory a vostra discrezione. Per ulteriori informazioni in merito ala configurazione dei Virtualhosts, è possibile fare riferimento alla Apache's online documentation.

Invio geocoordinate al Web server

Possiamo ora procedere alla realizzazione dell'app per Windows Phone 8.1. Nel codice sorgente allegato all'articolo, troverete tale progetto sotto la cartella «FollowMe». In essa abbiamo due pagine: una dedicata alla parte di check-in, mentre la seconda verrà utilizzata per la parametrizzazione delle impostazioni dell'app, come l'URI da interrogare per raggiungere il web server. Su questo vedremo alcuni aspetti più tardi. La nostra app dovrà fare ciò che abbiamo eseguito manualmente poco sopra, ovvero calcolare dove il dispositivo si trovi, chiamando poi un URL avente la formattazione specifica a comunicare tali parametri al web server, dove la nostra web app attende.

Iniziamo con la pagina delle impostazioni. Essa contiene un TextBox per specificare l'URL da interrogare, ed una ComboBox per indicare la Culture da utilizzare durante l'invio delle coordinate. Possiamo scriverla come segue:

01.<Page
02.    x:Class="FollowMe.Settings"
03.    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
04.    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
05.    xmlns:local="using:FollowMe"
06.    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
07.    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
08.    mc:Ignorable="d"
09.    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
10.    Loaded="Page_Loaded">
11.    <Page.BottomAppBar>
12.        <CommandBar>
13.            <AppBarButton Icon="Accept" Label="Save" Click="AppBarButton_Click"/>
14.            <AppBarButton Icon="Cancel" Label="Cancel" Click="CancelButton_Click"/>
15.        </CommandBar>
16.    </Page.BottomAppBar>
17. 
18.    <Grid x:Name="LayoutRoot">
19. 
20.        <Grid.ChildrenTransitions>
21.            <TransitionCollection>
22.                <EntranceThemeTransition/>
23.            </TransitionCollection>
24.        </Grid.ChildrenTransitions>
25. 
26.        <Grid.RowDefinitions>
27.            <RowDefinition Height="Auto"/>
28.            <RowDefinition Height="*"/>
29.        </Grid.RowDefinitions>
30. 
31.        <!-- Title Panel -->
32.        <StackPanel Grid.Row="0" Margin="19,0,0,0">
33.            <TextBlock Text="FollowMe" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
34.            <TextBlock Text="Settings" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>
35.        </StackPanel>
36. 
37.        <TextBlock HorizontalAlignment="Left" Margin="19,9.833,0,0" Grid.Row="1" TextWrapping="Wrap" Text="Web service URI" VerticalAlignment="Top" FontFamily="Segoe WP" FontSize="18"/>
38.        <TextBox x:Name="txtWebUri" HorizontalAlignment="Left" Margin="19,38.833,0,0" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="362" PlaceholderText="http://localhost/"/>
39.        <TextBlock HorizontalAlignment="Left" Margin="19,103.833,0,0" Grid.Row="1" TextWrapping="Wrap" Text="Culture for coordinates" VerticalAlignment="Top" FontFamily="Segoe WP" FontSize="18"/>
40.        <ComboBox x:Name="cmbLang" HorizontalAlignment="Left" Margin="19,122.833,0,0" Grid.Row="1" VerticalAlignment="Top" Width="182">
41.            <x:String>it-IT</x:String>
42.            <x:String>en-US</x:String>
43.        </ComboBox>
44.    </Grid>
45.</Page>

Si noti l'aggiunta di un CommandBar per la gestione di due AppBarButton, uno per salvare le impostazioni specificate, ed il secondo per annullarle, semplicemente chiudendo la pagina. 
Il code-behind della nostra pagina sarà:

01.using FollowMe.Common;
02.using System;
03.using Windows.Storage;
04.using Windows.UI.Xaml;
05.using Windows.UI.Xaml.Controls;
06.using Windows.UI.Xaml.Navigation;
07. 
08.namespace FollowMe
09.{
10. 
11.    public sealed  partial class  Settings : Page
12.    {
13.        private NavigationHelper navigationHelper;
14.        private ObservableDictionary defaultViewModel = new ObservableDictionary();
15. 
16.        public Settings()
17.        {
18.            this.InitializeComponent();
19. 
20.            this.navigationHelper = new  NavigationHelper(this);
21.            this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
22.            this.navigationHelper.SaveState += this.NavigationHelper_SaveState;
23.        }
24. 
25.        private void  NavigationHelper_SaveState(object sender, SaveStateEventArgs e)
26.        {
27.        }
28. 
29.        private void  NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
30.        {
31.        }
32. 
33.        public NavigationHelper NavigationHelper
34.        {
35.            get { return this.navigationHelper; }
36.        }
37. 
38.        public ObservableDictionary DefaultViewModel
39.        {
40.            get { return this.defaultViewModel; }
41.        }
42. 
43. 
44.         #region NavigationHelper registration
45. 
46.        protected override  void OnNavigatedTo(NavigationEventArgs e)
47.        {
48.            this.navigationHelper.OnNavigatedTo(e);
49.        }
50. 
51.        protected override  void OnNavigatedFrom(NavigationEventArgs e)
52.        {
53.            this.navigationHelper.OnNavigatedFrom(e);
54.        }
55. 
56.        #endregion
57. 
58.        private void  AppBarButton_Click(object sender, RoutedEventArgs e)
59.        {
60.            var ap = ApplicationData.Current.LocalSettings;
61.            ap.Values["WebURI"] = txtWebUri.Text;
62.            ap.Values["Language"] = cmbLang.SelectedValue.ToString();
63. 
64.            Frame.Navigate(typeof(MainPage));
65.        }
66. 
67.        private void  Page_Loaded(object  sender, RoutedEventArgs e)
68.        {
69.            var ap = ApplicationData.Current.LocalSettings;
70.            try
71.            {
72.                txtWebUri.Text = ap.Values["WebURI"].ToString();
73.                cmbLang.SelectedValue = ap.Values["Language"].ToString();
74.            }
75.            catch {
76.            }
77.        }
78. 
79.        private void  CancelButton_Click(object sender, RoutedEventArgs e)
80.        {
81.            Frame.Navigate(typeof(MainPage));
82.        }
83.    }
84.}

Molto semplicemente, tutta la logica della pagina Settings ruota intorno all'evento Click dei due AppBarButton: il bottone per l'annullamento esegue la chiusura della pagina, ed un ritorno alla MainPage, mentre il bottone di salvataggio scrive nei LocalSettings della nostra app (da namespace Windows.Storage) i parametri che avremo indicato nel TextBox txtWebUri TextBox e nella ComboBox cmbLang, per poi eseguire un ritorno alla MainPage.

La pagina MainPage è il cuore dell'app. È costituita semplicemente da un bottone, un TextBox per eventuali note che l'utente vorrà indicare, e due TextBlocks in cui esporremo le geocoordinate (ma solo a scopo di debug, senza alcuna necessità reale in campo operativo). Vediamo il codice XAML di MainPage:

01.<Page
02.    x:Class="FollowMe.MainPage"
03.    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
04.    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
05.    xmlns:local="using:FollowMe"
06.    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
07.    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
08.    mc:Ignorable="d">
09.    <Page.BottomAppBar>
10.        <CommandBar>
11.            <AppBarButton Icon="Manage" Label="Settings" Click="AppBarButton_Click"/>
12.        </CommandBar>
13.    </Page.BottomAppBar>
14. 
15.    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
16.        <Button Content="Check in" Click="button1_Click"
17.            HorizontalAlignment="Left" Margin="10,381,0,0" Name="button1" VerticalAlignment="Top" Height="117" Width="380" />
18. 
19.        <TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="FollowMe" VerticalAlignment="Top" FontFamily="Segoe WP" FontSize="28" FontWeight="Bold"/>
20.        <TextBox Name="txtNotes" HorizontalAlignment="Left" Margin="10,69,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="380" PlaceholderText="Type any notes here"/>
21. 
22.        <TextBlock HorizontalAlignment="Left" Margin="10,130,0,0" TextWrapping="Wrap" Text="Latitude" VerticalAlignment="Top"/>
23.        <TextBlock HorizontalAlignment="Left" Margin="10,152,0,0" TextWrapping="Wrap" Text="Longitude" VerticalAlignment="Top"/>
24.        <TextBlock x:Name="lblLatitude" HorizontalAlignment="Left" Margin="104,130,0,0" TextWrapping="Wrap" Text="0.00000000" VerticalAlignment="Top"/>
25.        <TextBlock x:Name="lblLongitude" HorizontalAlignment="Left" Margin="104,152,0,0" TextWrapping="Wrap" Text="0.00000000" VerticalAlignment="Top"/>
26. 
27.    </Grid>
28.</Page>

Un AppBarButton ci consentirà di accedere alla pagina Settings. Non sono qui visibili altre particolarità. L'unica cosa che ci porta alla considerazione del code-behind della pagina è la presenza di un evento Click sull'unico Button presente. 

01.using System;
02.using Windows.UI.Xaml;
03.using Windows.UI.Xaml.Controls;
04.using Windows.Devices.Geolocation;
05.using Windows.Web.Http;
06.using Windows.UI.Popups;
07.using System.Globalization;
08.using Windows.Security.ExchangeActiveSyncProvisioning;
09.using Windows.Storage;
10. 
11.namespace FollowMe
12.{
13.    public sealed  partial class  MainPage : Page
14.    {
15.        Geolocator geo = null;
16. 
17.        public MainPage()
18.        {
19.            this.InitializeComponent();
20.        }
21. 
22. 
23.        private async void button1_Click(object sender, RoutedEventArgs e)
24.        {
25.            geo = new  Geolocator();
26.            bool isErr = false;
27.            string errMsg = "";
28. 
29.            button1.IsEnabled = false;
30. 
31.            try
32.            {
33.                Geoposition pos = await geo.GetGeopositionAsync();
34.                double lat = pos.Coordinate.Point.Position.Latitude;
35.                double lon = pos.Coordinate.Point.Position.Longitude;
36. 
37.                lblLatitude.Text = lat.ToString();
38.                lblLongitude.Text = lon.ToString();
39. 
40.                var ap = ApplicationData.Current.LocalSettings;
41. 
42.                CultureInfo cI = new  CultureInfo(ap.Values["Language"].ToString());
43. 
44.                String devName = new  EasClientDeviceInformation().FriendlyName;
45.                 
46.                HttpClient hwc = new  HttpClient();
47.                Uri myAddress = new  Uri(ap.Values["WebURI"].ToString() + "?lt=" +
48.                    lat.ToString(cI.NumberFormat) +
49.                    "&ln=" + lon.ToString(cI.NumberFormat) +
50.                    "&d=" + devName + "&n=" + txtNotes.Text);
51. 
52.                HttpResponseMessage x = await hwc.GetAsync(myAddress);
53.                 
54.            }
55.            catch (Exception ex)
56.            {
57.                isErr = true;
58.                errMsg = ex.Message;
59.            }
60. 
61.            if (isErr)
62.            {
63.                var dialog = new  MessageDialog(errMsg);
64.                await dialog.ShowAsync();
65.            }
66. 
67.            button1.IsEnabled = true;
68.            geo = null;
69.        }
70. 
71.        private void  AppBarButton_Click(object sender, RoutedEventArgs e)
72.        {
73.            Frame.Navigate(typeof(Settings));
74.        }
75. 
76.    }
77.}

Nel cliccare button1, viene impostata una nuova istanza di Geolocator. Da essa, tenteremo un recupero asincrono della posizione del dispositivo, leggendo latitudine e longitudine per scriverne i valori sui TextBlocks preposti. Con le linee da 25 a 26, abbiamo tutto ciò che server per geolocalizzare, mentre il resto del codice tratta la connessione al web server remoto. Per prima cosa, accediamo alle LocalSettings dell'applicazione, per leggere i parametri relativi all'URI da contattare ed ai parametri di lingua per inizializzare successivamente la Culture opportuna. Questo ci servirà per capire in quale formato dovremmo passare le geocoordinate (principalmente per una questione legata al diverso modo di specificare il separatore decimale, ad esempio tra la Culture italiana, che usa la virgola, e la statunitense, che fa uso del punto).

Successivamente, tramite la classe EasClientDeviceInformation, estraiamo il FriendlyName del dispositivo, ovvero il suo nome, così come indicato nelle impostazioni del dispositivo stesso (line 44). Quindi, creeremo una richiesta web tramite la classe HttpClient, richiamando un URI precedentemente forgiato (linee da 46 a 52), nel quale specificare le coordinate, il nome di dispositivo, e le eventuali note come parametri GET, nel modo in cui la nostra pagina PHP se le aspetta.

In caso dovesse emergere un qualsiasi errore, un MessageDialog di dettaglio verrà emesso a scopo informativo.

IMPORTANTE: per fare in modo che tutto funzioni correttamente, si dovranno verificare due aspetti fondamentali. Il primo, è ovviamente di avere attivi sul proprio dispositivo i servizi di localizzazione. Il secondo è l'abilitazione delle capability di geolocalizzazione nell'app. Nel vostro progetto, dovrete cioè cliccare due volte sul file package.appxmanifest, selezionando il tab Capabilities. In esso, si dovrà spuntare il parametro Location nella lista delle capabilities. Senza di esso, il servizio di geolocalizzazione risulterà inaccessibile all'app..

Questo è quanto: si tratta di un'app tutto sommato molto semplice, con diverse migliorie che possono venirle applicate. Allo stato attuale, essa è comunque sufficiente per i nostri scopi.

Esaminare i dati raccolti

Come abbiamo visto, quando la nostra app esegue una richiesta web un nuovo record viene inserito nel database remoto. Ciò che ci serve ora è uno strumento attraverso cui esaminare i dati memorizzati. Lo snippet che segue realizza una semplice pagina HTML, contenente una tabella che avrà una riga per ogni record inserito. Mostrerà la data e ora in cui un determinato record è stato inserito, le coordinate, il nome del dispositivo, le note dell'utente. In ultimo, ciascuna riga presenterà un link per navigare ad una pagina in cui presenteremo una mappa, corredata da marker grafico sulla posizione del dispositivo. Tale pagina avrà nome "geolist.php"
   

01.<html>
02.   <head>
03.      <title>GeoLog</title>      
04.      <!-- OMITTED: CSS part, you'll find it in the complete source code -->
05.   </head>
06. 
07.   <body>
08.      <table>
09.         <tr>
10.            <th>Id</th>
11.            <th>Date</th>
12.            <th>Lat.</th>
13.            <th>Long.</th>
14.            <th>Device</th>
15.            <th>Annotations</th>
16.            <th>Map</th>
17.         </tr>
18.          
19.         <?php
20. 
21.          //-- Connecting to "geolog" database, on "localhost" server
22.          $mysqli = new mysqli('localhost', '<USER>',  '<PASSWORD>',  'geolog');
23.          if ($mysqli->connect_errno) {
24.             echo "Failed to connect to MySQL: ("  . $mysqli->connect_errno . ") " .  $mysqli->connect_error;
25.             exit();
26.          }
27. 
28.          //-- Declaring and executing a SELECT on "entries" table, to retrieve all the records in it
29.          $query = "SELECT * FROM entries ORDER BY IdEntry";
30.          $result = $mysqli->query($query);
31. 
32.          //-- For each retrieved record, we'll add to the DOM a table row, containing the read values
33.          while($row = $result->fetch_array()){ ?>
34.           
35.             <tr>
36.                <td><?php echo $row['IdEntry'];?></td>
37.                <td><?php echo $row['TimeStamp'];?></td>
38.                <td><?php echo $row['Latitude'];?></td>
39.                <td><?php echo $row['Longitude'];?></td>
40.                <td><?php echo $row['Device'];?></td>
41.                <td><?php echo $row['Annotation'];?></td>
42.                <td>[<a href="map.php?lt=<?php echo $row['Latitude'];?>&ln=<?php echo $row['Longitude'];?>&d=<?php echo $row['Device'];?>&n=<?php echo $row['Annotation'];?>">Link</a>]</td>
43.             </tr>
44.          <?php }
45. 
46.          //-- Close connection / cleanup
47.          $result->close();
48.          $mysqli->close();
49.         ?>
50.   </body>

Omettendo la parte legata agli stili grafici, ciò che viene fatto in questa sede è stabilire la connessione verso il nostro database MySQL (ovvero "geolog") per procedere poi all'interrogazione della tabella "entries". Per ciascun record, creeremo una riga di tabella con i propri elementi figlio: sei celle che esporranno i dati letti. Il link finale su ciascuna riga punta ad una pagina denominata "map.php". Tale pagina è quella in cui realizzeremo la renderizzazione della mappa relativa alle coordinate indicate. Vediamone il codice.

01.<?php
02.   $latitude   = $_GET['lt'];
03.   $longitude  = $_GET['ln'];
04.   $device     = $_GET['d'];
05.   $annotation = $_GET['n'];
06.?>
07. 
08.<html>
09.  <head>
10.    <title>GeoLog</title>
11.    <meta name="viewport"  content="initial-scale=1.0, user-scalable=no">
12.    <meta charset="utf-8">
13.    <style>
14.      html, body, #map {
15.        height: 100%;
16.        margin: 0px;
17.        padding: 0px;
18.        width:100%;
19.      }
20.    </style>
21.    <script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true&language=it"></script>
22.    <script>
23.       var initialize = function(){
24.           var latlng = new google.maps.LatLng(<?php echo $latitude,  ",", $longitude;?>);
25.           var options = { zoom: 18,
26.                           center: latlng,
27.                           mapTypeId: google.maps.MapTypeId.ROADMAP
28.                         };
29.           var map = new google.maps.Map(document.getElementById('map'), options);
30.            
31.           var marker = new google.maps.Marker({ position: latlng,
32.                                                 map: map, 
33.                                                 title: '<?php echo $device;?>'  });
34.       }
35.        
36.       window.onload = initialize;
37.    </script>
38.  </head>
39.  <body>
40.     <div id="map"></div>
41.  </body>
42.</html>

Per evitare una seconda query sul database, utilizzeremo il metodo GET per passare alla pagina map.php tutte le informazioni di cui necessita. La pagina fa uso di JavaScript, attingendo ad alcune API di Google Places (developers reference). Il funzionamento è come segue: viene creata una mappa a partire dalla latitudine/longitudine, assegnandola ad un DIV come contenitore per il rendering grafico. Successivamente, viene creato un oggetto Marker sulla locazione specifica. Dal momento che utilizziamo qui parametri di una richiesta GET, utilizziamo un piccolo espediente: JavaScript viene eseguito client-side,sulla macchina dell'utente; PHP viene eseguito server-side. Di conseguenza, introducendo istruzioni PHP queste verranno eseguite prima di quelle JavaScript, e quando la pagina "arriverà" sul dispositivo dell'utente finale, sarà già stata modificata dall'esecuzione PHP remota. In questo modo, possiamo semplicemente eseguire un echo delle variabili GET come parametri di JavaScript, ed essi verranno compilati nel codice che sarà poi eseguito client-side, permettendo la visualizzazione della mappa.

Test completo

Possiamo ora "confezionare" il tutto ed eseguire un test completo. Per prima cosa, apriamo la nostra app WP sul dispositivo mobile, configurandola verso l'URI precedentemente predisposto. Poi, cliccheremo sul tasto «Check-in» per iniziare la geolocalizzazione e la richiesta web. In questa fase, la nostra app assemblerà l'URI da richiamare, procedendo poi nel visitarlo, e quindi lanciando l'evento remoto di INSERT del dato.

  

Ora apriamo un brower, e visitiamo la pagina geolist.php page, per esaminare i record inseriti. Verrà mostrato il nostro recente check-in, e potremo quindi cliccare sul suo link per aprire la pagina map.php, che ci mostrerà graficamente la posizione precedentemente salvata.


   

Codice sorgente

Il codice sorgente usato nell'articolo può essere scaricato da: https://code.msdn.microsoft.com/Geolocalize-a-device-and-dae0d265

Bibliografia

Altre lingue

Il presente articolo è disponibile nelle seguenti localizzazioni: