6. Phoogle, file_get_contents() y allow_url_fopen

Estimado visitante número n,

Finalmente, después de haber hecho no recuerdo qué, he podido trabajar correctamente con Phoogle en mi servidor local. Digo correctamente en el sentido de que el ayudante hace lo que yo, usuario, espero que haga; es decir, que este “correctamente” es relativo. El ayudante Google Maps Phoogle me ha ayudado mucho, valga la redundancia. Pero no nos desviemos: en este post explico otro herror, de esos horribles, imbatibles por la ignorancia de uno. 

Hace un par o tres de semanas -espero no haber metido mucho la pata- explicaba los problemitas que me había encontrado al trabajar con esta clase. Recuerdo, por ejemplo, que si se me ocurría poner direcciones inexistentes, entonces PHP lanzaba algunos avisos. Desde que utilizo la última versión del ayudante Phoogle, disponible aquí, esto ya no sucede y Phoogle funciona perfectamente en mi servidor local; el herror horrible aparece en mi servidor compartido, cuando el ínterprete de PHP intenta interpretar -valga la redundancia otra vez- esta línea del programa:


$addressData = file_get_contents($apiURL.urlencode($address));

Como mi servidor compartido tiene deshabilitada la directiva allow_url_fopen, aparece un herror como este:

Warning (2): file_get_contents() [function.file-get-contents]: URL file-access is disabled in the server configuration [APP/views/helpers/phoogle.php, line 129] ¡Puaj!

Me gustaría poder utilizar Phoogle en mi servidor compartido tal y como está ahora, sin tener que hacer ninguna modificación, pero no sé cómo hacerlo. Si tú estás como yo, probablemente sabrás que la función file_get_contents() hace esto y que la directiva allow_url_fopen sirve para esto otro; si no lo estás, y sabes cómo salir de aquí, seguramente puedes dejar algún comentario para iluminarnos, jeje.

Gracias de antemano y un saludo.

5. Pequeño error con las direcciones inexistentes en Phoogle

El 30 de octubre de 2008 dejaba un mensaje en el Grupo Google CakePHP en Español explicando que tenía un problema porque el helper Phoogle no funcionaba cuando el usuario introducía una dirección inexistente. Pues bien, en este post propongo una solución; allá va:

Después de instalar el ayudante Phoogle empecé a hacer algunas pruebas, introduciendo direcciones vacías e inexistentes, y PHP lanzaba varios avisos. Para eliminar los de tipo Use of undefined constant Response hay que poner comillas simples en todos los Response del método addAddress.

A continación, después de este cambio, si uno vuelve a probar la clase e introduce una dirección inexistente, PHP lanza dos avisos de tipo Undefined index que corresponen a las dos líneas del método addAddress recién cambiadas.

La responsable es esta línea,

 $results = $this->xml2array(utf8_encode($addressData)); 

junto con el tratamiento que le da el método addAddress, que puedes ver aquí

 

Esta instrucción convierte el documento XML de Google en una matriz asociativa y utiliza el método xml2array de la clase assoc_array2xml -el autor de esta clase es Roger Veciana, está distribuida bajo la licencia BSD y puede obtenerse en www.phpclasses.org-.

Sucede que las etiquetas del XML que envía Google varían, dependiendo de si la dirección que introduce el usuario existe o no, y, como consecuencia de esto, también lo hacen los índices de la matriz asociativa $results.

Si la dirección no existe, el contenido de $results es este:

 

Array ( [kml] => Array ( [Response] => Array ( [name] => [Status] => Array ( => 601 [request] => geocode ) ) ) )

 

porque el documento XML es el siguiente:

  

<?xml version=”1.0″ encoding=”UTF-8″ ?>

<kml xmlns=”http://earth.google.com/kml/2.0“>

<Response>

  <name>jkfowioj23</name>

<Status>

  <code>602</code>

  <request>geocode</request>

  </Status>

  </Response>

  </kml>

 

El método addAddress falla porque intenta obtener las coordenadas geográficas a partir de unas etiquetas que el documento XML anterior no tiene. Por otra parte, si la dirección existe, el contenido de $results es este:

  

Array ( [kml] => Array ( [Response] => Array ( [name] => barcelona sagrada familia 2 [Status] => Array ( => 200 [request] => geocode ) [Placemark] => Array ( [address] => Aviny , 20, 08002, Barcelona, Spain [AddressDetails] => Array ( [Country] => Array ( [CountryNameCode] => ES [CountryName] => Spain [AdministrativeArea] => Array ( [AdministrativeAreaName] => CT [SubAdministrativeArea] => Array ( [SubAdministrativeAreaName] => Barcelona [Locality] => Array ( [LocalityName] => Barcelona [Thoroughfare] => Array ( [ThoroughfareName] => Aviny 20 [AddressLine] => Sagrada Familia ) [PostalCode] => Array ( [PostalCodeNumber] => 08002 ) ) ) ) ) ) [ExtendedData] => Array ( [LatLonBox] => Array ( [north] => 41.381122 [south] => 41.381122 [east] => 2.176690 [west] => 2.176690 ) ) [Point] => Array ( [coordinates] => 2.176690,41.381122,0 ) ) ) ) )

 

porque ahora el documento XML es este:

  

<?xml version=”1.0″ encoding=”UTF-8″ ?>

<kml xmlns=”http://earth.google.com/kml/2.0“>

<Response>

  <name>barcelona gaudi 2</name>

<Status>

  <code>200</code>

  <request>geocode</request>

  </Status>

<Placemark id=”p1“>

  <address>Avinguda de Gaudí, 2, 08025, Barcelona, España</address>

<AddressDetails Accuracy=”8 xmlns=”urn:oasis:names:tc:ciq:xsdschema:xAL:2.0“>

<Country>

  <CountryNameCode>ES</CountryNameCode>

  <CountryName>España</CountryName>

<AdministrativeArea>

  <AdministrativeAreaName>CT</AdministrativeAreaName>

<SubAdministrativeArea>

  <SubAdministrativeAreaName>Barcelona</SubAdministrativeAreaName>

<Locality>

  <LocalityName>Barcelona</LocalityName>

<Thoroughfare>

  <ThoroughfareName>Avinguda de Gaudí 2</ThoroughfareName>

  </Thoroughfare>

<PostalCode>

  <PostalCodeNumber>08025</PostalCodeNumber>

  </PostalCode>

  </Locality>

  </SubAdministrativeArea>

  </AdministrativeArea>

  </Country>

  </AddressDetails>

<Point>

  <coordinates>2.174498,41.404616,0</coordinates>

  </Point>

  </Placemark>

  </Response>

  </kml>

 

Como no se pueden recuperar las coordenadas geográficas de una dirección incorrecta a partir de un XML como el primero, mi método addAddress modificado no trata estos puntos y queda así:

    

   function addAddress($address,$htmlMessage=null){
    if (!is_string($address)){
      die("All Addresses must be passed as a string");
     }
      $apiURL = "<a href="http://maps.google.com/maps/geo?&output=xml&key=&quot;.$this->apiKey.&quot;&q">http://maps.google.com/maps/geo?&output=xml&key=".$this->apiKey."&q</a>=";
      $addressData = file_get_contents($apiURL.urlencode($address));

      $results = $this->xml2array(utf8_encode($addressData));
      if (empty($results['kml']['Response']['Placemark']['Point']['coordinates'])){
         $pointer = count($this->validPoints);
         $this->validPoints[$pointer]['lat']= '19.4343';
         $this->validPoints[$pointer]['long']= '155.5854';
         $this->validPoints[$pointer]['passedAddress'] = $address;
         $this->validPoints[$pointer]['htmlMessage'] = $htmlMessage;
        }else{
         $pointer = count($this->validPoints);
         $this->validPoints[$pointer]['lat']= $results['kml']['Response']['Placemark']['Point']['coordinates'];
         $this->validPoints[$pointer]['long']= $results['kml']['Response']['Placemark']['Point']['coordinates'];
         $this->validPoints[$pointer]['passedAddress'] = $address;
         $this->validPoints[$pointer]['htmlMessage'] = $htmlMessage;
      }

   }

 

  

Si un usuario se equivoca en el momento de escribir la dirección, o la deja en blanco, la clase entenderá que se trata de un punto correcto, y, en vez de mostrar los avisos anteriores, presentará un mapa de referencia con las coordenadas 19.4343 y 155.58.54.

 

 

4. Helper Phoogle Maps para CakePHP

Hoy vamos a dar un paso importante con respecto a los dos posts anteriores y vamos a ver cómo integrar un ayudante Ajax en CakePHP para trabajar con Google Maps.

Justin Johnson es un desarrollador web que trabaja en www.systemsevendesigns.com. Ha programado una clase en PHP, Phoogle Maps (pronunciado Foogle Maps), que se integra con el API de Google y Yahoo! y facilita la visualización de mapas. Puedes descargarte esta clase aquí, haciendo clic en el enlace Download Phoogle Maps. Phoogle es el nombre de la clase PHP; para adaptar esta clase al framework CakePHP y convertirla en helper, o ayudante, hay que seguir estas explicaciones -hay dos-. Yo me descargué la versión 2 de Phoogle y seguí esta.

Mis pasos fueron estos:

1. Después de obtener la clase comprimida, copié el archivo phoogle.php en la carpeta views/helpers de mi aplicación Cake.

2. Edité el archivo phoogle.php y cambié la declaración de la clase:

Donde ponía esto:


class PhoogleMap{

escribí esto otro:


class PhoogleHelper extends Helper{

3. A continuación, edité el método de mi controlador, asociado al mapa, y cargué el ayudante Phoogle:


var $helpers = array('Phoogle'); 

Inicialicé la variable googleApiKey en este método, así:


$this->set('googleApiKey','tu_clave');

4. Edité el layout y puse esto, que escribe el código JavaScript que carga el API de Google:


if(isset($phoogle))
{
    $phoogle->setAPIKey($googleApiKey);
    $phoogle->printGoogleJS();
}

Este fragmento hay que insertarlo entre las etiquetas <head> y </head> del layout y sirve para cargar la versión 2 del API Google Maps -la versión se especifica en el parámetro v del URL-. El código que imprime el método printGoogleJS de la clase Phoogle es este:


<script src="http://maps.google.com/maps?file=api&v=2&key=tu_clave" type="text/javascript"></script>

5. Finalmente, escribí este fragmento de código en mi vista, dentro de la etiqueta:

<div id="map" style="width: 500px; height: 300px">


$phoogle->addAddress("Barcelona gaudi 2");

$phoogle->showMap();

Esto escribe en la vista el siguiente JavaScript:


      function showmap(){
            //<!&#91;CDATA&#91;

         if (GBrowserIsCompatible()) {

            var map = new GMap(document.getElementById("map"));
map.centerAndZoom(new GPoint(2.174498,41.404616,0,2.174498,41.404616,0), 4);
}

         var icon = new GIcon();
         icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
         icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
         icon.iconSize = new GSize(12, 20);
         icon.shadowSize = new GSize(22, 20);
         icon.iconAnchor = new GPoint(6, 20);
         icon.infoWindowAnchor = new GPoint(5, 1);

         map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
var point0 = new GPoint(2.174498,41.404616,0,2.174498,41.404616,0)
;
              var marker0 = new GMarker(point0);

              map.addOverlay(marker0)

              GEvent.addListener(marker0, "click", function() {
marker0.openInfoWindowHtml("Barcelona gaudi 2");
});
      //&#93;&#93;>

      }
      window.onload = showmap;

Phoogle ha geocodificado la dirección “Barcelona gaudi 2”; es decir, ha calculado los valores 2.174498 y 41.404616, las coordenadas geográficas de esta dirección, mediante su método addAddress:


/**
* @function     addAddress
* @param        $address:string
* @returns      Boolean True:False (True if address has long/lat, false if it doesn't)
* @description  Add's an address to be displayed on the Google Map
*               (thus eliminating the need for two different show methods from version 1.0)
*/
   function addAddress($address,$htmlMessage=null){
    if (!is_string($address)){
      die("All Addresses must be passed as a string");
     }
      $apiURL = "http://maps.google.com/maps/geo?&output=xml&key=".$this->apiKey."&q=";
      $addressData = file_get_contents($apiURL.urlencode($address));

      $results = $this->xml2array(utf8_encode($addressData));
      if (empty($results['kml'][Response]['Placemark']['Point']['coordinates'])){
         $pointer = count($this->invalidPoints);
         $this->invalidPoints[$pointer]['lat']= $results['kml'][Response]['Placemark']['Point']['coordinates'][0];
         $this->invalidPoints[$pointer]['long']= $results['kml'][Response]['Placemark']['Point']['coordinates'][1];
         $this->invalidPoints[$pointer]['passedAddress'] = $address;
         $this->invalidPoints[$pointer]['htmlMessage'] = $htmlMessage;
        }else{
         $pointer = count($this->validPoints);
         $this->validPoints[$pointer]['lat']= $results['kml'][Response]['Placemark']['Point']['coordinates'];
         $this->validPoints[$pointer]['long']= $results['kml'][Response]['Placemark']['Point']['coordinates'];
         $this->validPoints[$pointer]['passedAddress'] = $address;
         $this->validPoints[$pointer]['htmlMessage'] = $htmlMessage;
      }

   }

Este método hace una petición HTTP al geocodificador de Google, especificando los parámetros q -dirección que se quiere geocodificar-, key -clave API Google Maps- y output -formato de la respuesta-. La respuesta que se obtiene de Google es un documento XML parecido a este, que el método addAddress analiza sintácticamente:

<?xml version=”1.0″ encoding=”UTF-8″ ?>

<Response>
  <name>“Barcelona gaudi 2”</name>
<Status>
  <code>200</code>
  <request>geocode</request>
  </Status>
<Placemark id=”p1>
  <address>Avinguda de Gaudí, 2, 08025, Barcelona, España</address>
<AddressDetails Accuracy=”8 xmlns=”urn:oasis:names:tc:ciq:xsdschema:xAL:2.0>
<Country>
  <CountryNameCode>ES</CountryNameCode>
  <CountryName>España</CountryName>
<AdministrativeArea>
  <AdministrativeAreaName>CT</AdministrativeAreaName>
<SubAdministrativeArea>
  <SubAdministrativeAreaName>Barcelona</SubAdministrativeAreaName>
<Locality>
  <LocalityName>Barcelona</LocalityName>
<Thoroughfare>
  <ThoroughfareName>Avinguda de Gaudí 2</ThoroughfareName>
  </Thoroughfare>
<PostalCode>
  <PostalCodeNumber>08025</PostalCodeNumber>
  </PostalCode>
  </Locality>
  </SubAdministrativeArea>
  </AdministrativeArea>
  </Country>
  </AddressDetails>
<Point>
  <coordinates>2.174498,41.404616,0</coordinates>
  </Point>
  </Placemark>
  </Response>
  </kml>

Si todo sale bien, debería obtenerse un mapa de l’avinguda Gaudí de Barcelona, con la Sagrada Família al lado. Si encuentras algún error en este post o tienes algún problema instalando Phoogle puedes dejar aquí un comentario. ¡Suerte!

3. Mi primer mapa Google

Hoy crearemos nuestro primer mapa. Para ello, debemos copiar el código de ejemplo del post anterior -facilitado por Google en el momento de solicitar una clave para trabajar con el API-, pegarlo en un editor, y guardarlo con el nombre EjemploGoogle.html. Sólo hay que hacer un pequeño cambio: introducir nuestra clave en esta parte:


<script src="http://maps.google.com/maps?file=api&v=2&key=tuclave"

type="text/javascript">

</script>

Si cargamos la página EjemploGoogle.html en un navegador, veremos este mapa:

Esta es la Universidad de Stanford. Aquí se conocieron los creadores de Google, Larry Page y Sergey Brin.

Ahora vamos a editar el archivo EjemploGoogle.html y nos vamos a centrar en esta parte del código JavaScript, que pertenece a la función load():

var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);

Hacemos este pequeño cambio y lo dejamos así:

var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(41.387917,2.169919), 13);

¡Ya estamos trabajando con el API de Google! La primera línea crea un objeto de la clase JavaScript GMap2 y representa un mapa único en la página. El constructor de la clase GMap2 necesita un contenedor HTML para crear el objeto, que suele ser un elemento DIV. En otras palabras, decimos a Google: “Oye, por favor, créame un mapa y pónmelo en el “map” del HTML. Gracias.”.

La segunda línea sirve para inicializar el mapa. La clase JavaScript GMap2 implementa el método setCenter() y necesita una coordenada de tipo GLatLng. Nosotros hemos puesto aquí las coordenadas geográficas de la ciudad de Barcelona:

¿Que eres de Bilbao? Pues no pasa nada, escribes las coordenadas de tu ciudad en el código de ejemplo:

var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(43.256963,-2.923441), 13);

Y cargas el archivo EjemploGoogle.html en tu navegador:

¿Prefieres Madrid? Escribimos sus coordenadas geográficas en el código JavaScript:

var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(40.416741,-3.70325), 13);

 

Todo esto y más se explica aquí; nosotros continuamos en próximos posts.

2. Consigue una clave para trabajar con la API Google Maps

Para poder trabajar con la API tenemos que darnos de alta en el servicio y conseguir una clave, que, como veremos en futuros posts, se utiliza para identificar las peticiones. La clave se obtiene en la página de Inscripción para el API de Google Maps -hace falta tener una cuenta Google-.

Después de leer y aceptar las condiciones de uso podemos escribir el URL de nuestro sitio web: yo escribí la dirección de este blog, www.tutorialcakephp.wordpress.com. A continuación, en la página siguiente, tenemos que introducir nuestra cuenta: yo aquí puse la mía, jordicakephp@gmail.com.

Con estos datos Google genera la clave y nos da la bienvenida: “Thank you for signing up for a Google Maps API key!”; también nos facilita un código HTML de ejemplo para ver cómo se utiliza el script:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Google Maps JavaScript API Example</title>
    <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=tu clave"
      type="text/javascript"></script>
    <script type="text/javascript">
    //<![CDATA[
    function load() {
      if (GBrowserIsCompatible()) {
        var map = new GMap2(document.getElementById("map"));
        map.setCenter(new GLatLng(37.4419, -122.1419), 13);
      }
    }
    //]]>
    </script>
  </head>
  <body onload="load()" onunload="GUnload()">
    <div id="map" style="width: 500px; height: 300px"></div>
  </body>
</html>

La página de bienvenida a la documentación para programadores del API de Google Maps explica cómo utilizar las instrucciones del API. Nosotros lo hacemos en próximos posts porque antes nos gustaría recordar, aquí, cómo funcionan las coordenadas geográficas; también dejamos esta tabla con las coordenadas de algunas ciudades españolas:

Ciudad

N

E

Barcelona

41.387917

2.169919

Bilbao

43.256963

-2.923441

Madrid

40.416741

-3.70325

Sevilla

37.38264

-5.996295

1. Incrusta Google Maps en tu sitio web o blog

Vamos a seguir los pasos de Google para incrustar un mapa en una página web sin necesidad de programar ni utilizar la API.

1. Vamos a http://maps.google.es y escribimos la dirección que queramos en el cuadro de búsqueda -yo aquí puse la Plaça Catalunya de Barcelona-.

2. A continuación, cuando aparece el mapa, hacemos clic en Enlazar, en la parte derecha de la pantalla.

3. Aparece un cuadro con la opción Pegar HTML para insertar en sitio web: seleccionamos el texto que hay dentro y lo copiamos.

¡Ya podemos pegar el código en el HTML de nuestro sitio web para ver el mapa!