designing4u.de Yet Another Coding Blog

4Aug/0821

Google Maps, jQuery and XML – saving markers with user input

I just got a first request from a user of my site to help him with his problem. Let me describe it in detail. Assume that a user is visiting your site and he or she wants to place a marker on a google map displayed on your page. Additionally, we want to get some input from our user, therefore after he or she clicks on the google map we will provide an info could with a form. Our user will be able to provide a name, a message and a link and submit it. I didn't want to make this example too complicated, therefore handling the links or uploading the files you will have to solve by yourself. Let's move to the code.

Our final solution will look more or less like this.

In our example we will use two file types - PHP and XML. Our PHP file will be responsible for saving the user input in XML file and displaying the google map with all saved markers. Our XML file will be basically a place, where we will save all the markers saved by an user. It is worth to mention that you can easily replace the XML file with any kind of a database. If you do so, you will for example have possibility to approve each marker saved on your page. Additionally, if you have some kind of authentication system on your site, you can also save according username of a person who placed a marker on your site and provide some kind of statistics for your users. It's up to you, how you will use this code.

After some initial explanation we can move to our PHP file. Let's start with the header of our file:

1. PHP file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (isset($_POST['submit'])) {
  $fh = file_get_contents('markers.xml');
 
  try {
    $xml = new SimpleXMLElement($fh);
  } catch (Exception $e) {
    echo $e->getMessage();
  }
 
  $marker = $xml->addChild('marker');
  $marker->addAttribute('lat', $_POST['lat']);
  $marker->addAttribute('lng', $_POST['lng']);
  $marker->addAttribute('msg', utf8_encode($_POST['msg']));
  $marker->addAttribute('name', utf8_encode($_POST['name']));
  $marker->addAttribute('link', utf8_encode($_POST['link']));
 
  $fp = fopen('markers.xml','w');
  fwrite($fp, $xml->saveXML());
  fclose($fp);
  header('Location:index.php');
}

We use PHP function file_get_contents() to load the content of our XML file. Our XML file would be an empty XML file with markers element, which will be a holder for our markers. We initialize a PHP build in class SimpleXMLElement with our file and catch an exception if any error occur. If our user clicks on a save button (the code of this form will follow) we create a child element with according attributes and then save it as a new XML file.

This way we will add new markers to our XML file without loosing any previous information saved in our XML file. After our file is saved we redirect our user to the index page to prevent reloading of the page and saving multiple markers with the same information. I know it is not the cleanest way to do that, but it is just an example which should serve as a blueprint for your code.

You can notice that I use utf8_encode() function to encode our user input into correct charset. Because I encountered major problems with foreign characters and our final solution should work for standard characters as well as for special characters, that is a necessary step to handle this problem. The only thing you should keep in mind is to set the charset of your site to UTF-8.

Don't forget to put that code before the head section of your PHP file, because otherwise you will get an error that the header were already send.

Let's take a look at our jQuery function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
$(document).ready(function() {
 
  var mark;
  var pointA;
 
  if (GBrowserIsCompatible()) {
    var m = $("#map")[0];
 
    if(m) {
 
      var map = new GMap2(m);
      var start = new GLatLng(63.13450320833446,16.69921875);
      var zoomLevel = 5;
      map.setCenter(start, zoomLevel);
      map.addControl(new GSmallMapControl());
 
      $.get('markers.xml',function(data) {
        $(data).find('marker').each(function(){
          var lat    = $(this).attr('lat');
          var lng    = $(this).attr('lng');
          var html   = $(this).attr('name')+" ";
          html      += $(this).attr('msg')+" ";
          html      += $(this).attr('link');
          var point  = new GLatLng(lat,lng);
          var marker = new GMarker(point);
 
          map.addOverlay(marker);
 
          GEvent.addListener(marker, "click", function() {
            marker.openInfoWindowHtml(html);
          });
 
        });
 
      });
 
      GEvent.addListener(map, 'click', function(overlay, point){
        if(mark) {
          map.removeOverlay(mark);
        }
        if(point) {
          pointA = new GPoint(point.x, point.y);
          mark = new GMarker(pointA);
          map.addOverlay(mark);
          map.getCenter(point);
          var lat = point.y;
          var lng = point.x;
          var form = "
          <form action="\"index.php\"" method="\"post\"">" +
          "<input name="\"lat\"" type="\"hidden\"" value="\""+lat+"\"" />"+
          "<input name="\"lng\"" type="\"hidden\"" value="\""+lng+"\"" />"+
          "Name:
          <input name="\"name\"" type="\"text\"" value="\"\"" />"+
          "Msg:
          <input name="\"msg\"" type="\"text\"" value="\"\"" />"+
          "Link:
          <input name="\"link\"" type="\"text\"" value="\"\"" />"+
          "<input name="\"submit\"" type="\"submit\"" value="\"save\"" />"+
          "</form>";
          map.openInfoWindowHtml(point,form);
        }
      });
    }
  }
});

In the first part we declare two variables pointA and mark which will later serve to retrieve the longitude and latitude of our marker. We will also reduce the ability of a user to place several markers at the same time.

We check if our browser is compatible with google maps and we look for a place holder for our map. If both of the conditions are fulfilled we display our map and use AJAX request to display all the markers saved in our XML file. We also add an event listener which is triggered every time a user clicks on an existing marker. If it is a case, we display an info cloud with information saved by the user.

In the second part of our function we add another event listener, which is triggered every time a user places a new marker. In our info cloud we will display a form which I mentioned before and save the longitude and latitude in hidden fields. After our user clicks a save button the information from the form will be processed by our PHP file which will create another marker and display it on our google map.

The last part is our XML file:

2. XML file:

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<markers>
<marker lat="64.4348920430406" lng="15.205078125" msg="Msg" name="Name" link="yes!"/>
</markers>

As I said before this example is just a blueprint and should be extended by user input validation. As I also said before, you don't really need to use XML file and you can also implement an approval system of each marker placed on your site. You will have to save your information in a database though. You can use my post about displaying a simple navigation to get the idea, how to create an XML file based on information you retrieve from database. I hope this will be helpful. I'm waiting for your feedback.

Comments (21) Trackbacks (1)
  1. thnx for all information

  2. but where is index2.php?

  3. huh? can you specify your question? Otherwise comments like this one will be removed!!!

    edit:
    you don’t nees index2.php. It’s really simple, you save all the input data from request in markers.xml file and redirect to the referer file again to avoid the problem with refreshing the page by a user and saving unnecessary information.

  4. Hi, thanks for the tutorial.
    Just one dude: the markers donĀ“t save, when i refresh the page the map is empty.

    Can you help me please?

  5. Hi, I am trying to do this exercise but I cant reda or write the XML file. At least I`ve downloaded your files but the same thing:
    - http://www.designing4u.de/examples/marker-gmap/index.php
    - http://www.designing4u.de/examples/marker-gmap/markers.xml
    -
    The only thing I`ve changed is the api key. But it doesnt work. The markers I`ve saved doesnt appear. Please can You help me. Thanks a lot.
    (My files are stored in http://www.ros-asociados.com/googlemaps and their names are index.php, markers.xml and jquery-latest.js)

  6. Ey, why do you delete our comments?

  7. Hi iSus!

    Sorry for a late response, but I was really busy with work.

    First of all I want to explain my previous answer. Nex asked where is index2.php file. If you go through the tutorial you will see that index2.php wasn’t mentioned in it at all, therefore my frustration. Did he really read it or what??

    To your question iSus. In my browser (FF3) everything works just fine. In the crap browsers like IE, you should know that they need unique names for files you load through AJAX request. Therefore rewrite the function to call unique file every time you call the $.get function. It could look more or less like that:

    var ts = new Date().getTime();
    $.get(‘markers.xml’, { time: ts }, function …

    I hope it will help.

  8. @cristobal

    I think it is not enough to just copy the files. You also need to add the php part at the top of the file and change it according to your needs. After that everything should work fine.

  9. Good info. I am trying your code as a base for allowing public input to my site.

    I’ve adjusted marker.xml to marker_input.php to point to my database in MySQL.

    Running into some odd anamolies;
    The point drop does allow input to my database however without any info to include no input to the coords other than 0.00000

    I’m suspecting its my misunderstanding of the php snippet you spoke of to add to the header. Admittedly Im new to jQuery and need to research that.

    Where are you inputting that php header you spoke of?

  10. You just need to do all of your data manipulation before any headers will be sent to be able to redirect a user to the same site. I’ve done that to avoid refreshing a page and placing another marker in the same spot.

    If you have a problem. there are plenty of ways to debug your application. As far as I know, Google allows only 20.000 requests a day for free, so if you have high traffic on your site that might be the first problem.

    I would just start with JavaScript. Try to alert() the lat and lng variables. If the alert box will show 0.00000 then it is a problem with Google Maps. If it wont try to debug php.

    Instead of saving the data try to var_dump() the _POST array and check if all the data is passed correctly. If it is then it has to be a problem with saving the data in database. Check the type of the field in your database. Check if you can insert this data manually either through cli or query browser or any other program which can handle that. If it wont help I cannot really help you any further without having a look at it.

  11. i would like to use two maps in my website.one map say map-1 should get the input from user through the marker and it should be stored in database.the information stored in the database should be retrieved and displayed on other map say map-2. please help me with a solution

  12. @sjp

    without knowing, how you want to handle saving and retrieving the data, it is hard to find an answer. Probably it should be pretty easy with AJAX instead of reloading the page every time. Basically you can create an instance of map1 and map2 with:

    var map1 = new GMap2(mapContainer1)
    var map2 = new GMap2(mapContainer2)

    and follow the naming convention to retrieve the information from map1 and display it on map2. If you provide me more information, maybe I can help you further.

  13. Very nice code. I have implemented it on a test site I’m working on but have ran into a dead end. I have been trying to write a function to easily delete markers.

    Any thoughts?

    Thanks again.

  14. @ash

    on what kind of user interaction do you want to delete these markers? If you just want to provide a delete button of a users marker, you need to identify him or her anyhow. If you just want to delete some of them, you either edit xml file or write GUI for editing it.

  15. Hey there, very nice code. I’ve ran into one issue I can’t get the markers to save even when I use your markers.xml and index.php with my api code. I thought it might be permissions but changed my markers.xml to 777 and still no workie.

    Any suggestions?

  16. @Jeff

    try to set error_reporting(E_ALL) and check, what kind of errors are you getting.

    You should also try to check, if your php is compiled with –enable-simplexml (should be by default).

    You can also check, which value is returned by a function extension_loaded(‘xml’).

    If you don’t have SimpleXML support, you should just build your xml file by creating it line by line, e.g.

    $xml = ‘‹markers lat=”…”›’;
    $xml .= ‘‹markers lat=”…”›’;

    and so on. I hope this helps. Let me know.

  17. Thanks for the help man! It was my fault… I didn’t have the php code at top of my index.php.

    Doh!

    Now I’m going to work on getting different types of markers for different objects.

  18. Hi, Does anyone know where can I find the similar solution support database?

  19. Hi Markus,

    if you want to support database just place your code in php file. Instead of file_get_contents() you just need to retrieve results from your database and return a string with xml header. I hope this helps.

  20. Thanks for the great tutorial… really informative! I just created an image uploader in the infowindow using the hidden iframe approach. I can get a thumbnail to appear in the infowindow and have the original image stored in a seperate folder, however I can’t get the thumbnail stored in the XML file and subsequently saved after submission of the form.

    My question for anyone, is if this is possible and what steps would I take to get this to function properly? Thanks in advance for any insights which could be provided.

    Kind regards

  21. @Sam

    Sorry for a late response. Of course it is possible. You just need to save the path to your image in the xml file. After all it is just a string, so It shouldn’t be a bigger problem to do it in php. I hope this helps.


Leave a comment

(required)