ProxySimplePHP

From OpenStreetMap Wiki
Jump to navigation Jump to search

User:Lizard wrote a simple caching-Proxy for OSM in PHP.

This should make it simple to use tiles in own projects (Deploying your own Slippy Map) without flooding the tiles-servers. You need to have curl installed.

tiles.php:

 <?php
    $ttl = 86400; //cache timeout in seconds
  
    $x = intval($_GET['x']);
    $y = intval($_GET['y']);
    $z = intval($_GET['z']);
    $r = strip_tags($_GET['r']);

    switch ($r)
    {
      case 'mapnik':
        $r = 'mapnik';
        break;
      case 'osma':
      default:
        $r = 'osma';
        break;
    }

    $file = "tiles/$r/${z}_${x}_$y.png";
    if (!is_file($file) || filemtime($file)<time()-(86400*30))
    {
      $server = array();
      switch ($r)
      {
      	case 'mapnik':
          $server[] = 'a.tile.openstreetmap.org';
          $server[] = 'b.tile.openstreetmap.org';
          $server[] = 'c.tile.openstreetmap.org';

          $url = 'http://'.$server[array_rand($server)];
          $url .= "/".$z."/".$x."/".$y.".png";
          break;
    
      	case 'osma':
      	default:
          $server[] = 'a.tah.openstreetmap.org';
          $server[] = 'b.tah.openstreetmap.org';
          $server[] = 'c.tah.openstreetmap.org';

          $url = 'http://'.$server[array_rand($server)].'/Tiles/tile.php';
          $url .= "/".$z."/".$x."/".$y.".png";
          break;
      }
      $ch = curl_init($url);
      $fp = fopen($file, "w");
      curl_setopt($ch, CURLOPT_FILE, $fp);
      curl_setopt($ch, CURLOPT_HEADER, 0);
      curl_exec($ch);
      curl_close($ch);
      fflush($fp);    // need to insert this line for proper output when tile is first requestet
      fclose($fp);
    }

    $exp_gmt = gmdate("D, d M Y H:i:s", time() + $ttl * 60) ." GMT";
    $mod_gmt = gmdate("D, d M Y H:i:s", filemtime($file)) ." GMT";
    header("Expires: " . $exp_gmt);
    header("Last-Modified: " . $mod_gmt);
    header("Cache-Control: public, max-age=" . $ttl * 60);
    // for MSIE 5
    header("Cache-Control: pre-check=" . $ttl * 60, FALSE);  
    header ('Content-Type: image/png');
    readfile($file);
  ?>

next, create a cache-directory and make it read/writeable

 mkdir tiles
 mkdir tiles/mapnik
 mkdir tiles/osma
 chmod -R 777 tiles

This supports URLS of the form http://www.youdomain.tld/tiles.php?z=15&x=17024&y=10792&r=mapnik

...but for URLs suitable for a slippy map (structured as per Slippy map tilenames) you will need a rewrite-rule, for example in .htaccess :

 RewriteEngine on
 RewriteRule ^tiles/([0-9]+)/([0-9]+)/([0-9]+).png$ tiles.php?z=$1&x=$2&y=$3 [L]

Test this in your browser with a tile URL such as http://www.youdomain.tld/tiles/15/17024/10792.png

If this gives you a tile image, then you're ready to point a Slippy Map installation (e.g. OpenLayers) at this caching proxy tile server!

Usage example with OpenLayers

In general, follow the instructions given in OpenLayers_Simple_Example. First create a new file like this one: OSM_LocalTileProxy.js

/**
 * Class: OpenLayers.Layer.OSM.MapnikLocalProxy
 *
 * Inherits from:
 *  - <OpenLayers.Layer.OSM>
 */
OpenLayers.Layer.OSM.MapnikLocalProxy = OpenLayers.Class(OpenLayers.Layer.OSM, {
    /**
     * Constructor: OpenLayers.Layer.OSM.MapnikLocalProxy
     *
     * Parameters:
     * name - {String}
     * options - {Object} Hashtable of extra options to tag onto the layer
     */
    initialize: function(name, options) {
        var url = [
            "http://yourProxyHost/tiles.php?z=${z}&x=${x}&y=${y}&r=mapnik"
        ];
        options = OpenLayers.Util.extend({ numZoomLevels: 19 }, options);
        var newArguments = [name, url, options];
        OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
    },

    CLASS_NAME: "OpenLayers.Layer.OSM.MapnikLocalProxy"
});

/**
 * Class: OpenLayers.Layer.OSM.OsmarenderLocalProxy
 *
 * Inherits from:
 *  - <OpenLayers.Layer.OSM>
 */
OpenLayers.Layer.OSM.OsmarenderLocalProxy = OpenLayers.Class(OpenLayers.Layer.OSM, {
    /**
     * Constructor: OpenLayers.Layer.OSM.OsmarenderLocalProxy
     *
     * Parameters:
     * name - {String}
     * options - {Object} Hashtable of extra options to tag onto the layer
     */
    initialize: function(name, options) {
        var url = [
            "http://yourProxyHost/tiles.php?z=${z}&x=${x}&y=${y}&r=osma"
        ];
        options = OpenLayers.Util.extend({ numZoomLevels: 18 }, options);
        var newArguments = [name, url, options];
        OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
    },

    CLASS_NAME: "OpenLayers.Layer.OSM.OsmarenderLocalProxy"
});

Now it's time to include the new layers for your proxy cache right after including OpenStreetMap.js by adding this line to your map page:

 <script src="openlayers/OSM_LocalTileProxy.js"></script>

The last step is to add these new layers to the other defined layers:

  layerMapnikLocalProxy = new OpenLayers.Layer.OSM.MapnikLocalProxy("Mapnik (local proxy)");
  map.addLayer(layerMapnikLocalProxy);
  
  layerTilesAtHomeLocalProxy = new OpenLayers.Layer.OSM.OsmarenderLocalProxy("Osmarender (local proxy)");
  map.addLayer(layerTilesAtHomeLocalProxy);