Key:uuid/Example Code

From OpenStreetMap Wiki
Jump to navigation Jump to search

Example Code to Automatically Tag OSM Objects

This example PHP cli script requires the php5-uuid module loaded, while there are pure php implementations of v4 UUID functions, using the OSSP library the php module is linked to should be more consistently random.

Output

In the sample output below, the script is using the dev server, the first time the script runs the UUID is added to the object, the next time any UUIDs are simply displayed.

# ./makeuuid.php node 268549131
uuid:amenity=a1b77379-37c0-46c1-ba70-8683c57493ac
# ./makeuuid.php node 268549131
uuid:amenity=a1b77379-37c0-46c1-ba70-8683c57493ac

Code

#!/usr/bin/php -q
<?
	$server = 'api06.dev.openstreetmap.org';
	$OSMuser = 'username';
	$OSMpass = 'password';

	$uuidtypes = array('operator', 'building', 'amenity', 'barrier', 'waterway', 'railway', 'bridge', 'tunnel', 'aeroway', 'aerialway',
				'power', 'man_made', 'leisure', 'office', 'shop', 'tourism', 'historic', 'landuse', 'military', 'natural', 'route',
				'boundary', 'crossing', 'mountain_pass', 'cutting', 'embankment', 'place');

	$setUUIDs = $UUIDs = array();

	if(intval($argc) != 3)
		die("Error!\n".$argv['0']." <object type> <object id>\n");

	$objtype = strtolower($argv['1']);
	$objid = intval($argv['2']);

	if($objtype != 'node' && $objtype != 'way' && $objtype != 'relation')
		$objtype = 'node';

	$url = 'http://'.$server.'/api/0.6/'.$objtype.'/'.$objid;
	$lines = explode("\n", trim(@file_get_contents($url)));

	if(count($lines) < 1 || $lines['0'] == '')
		die("No data returned from OSM server\n");

	$lines['0'] = '<osmChange version="0.6" generator="makeuuid.php">';
	$lines['1'] = '<modify>';
	list($type, $rest) = explode(' ', trim($lines['2']), 2);
	$lines['2'] = $type.' action="modify" '.$rest;
	unset($lines[count($lines)-1]);
	$close = $lines[count($lines)-1];
	unset($lines[count($lines)-1]);

	foreach($lines as $line)
	{
		$line = trim($line);
		if(substr($line, 0, 5) == '<tag ')
		{
			list($crud, $key) = explode(' k="', $line, 2);
			list($key, $val) = explode('" v="', $key, 2);
			list($val, $crud) = explode('"', $val, 2);
			if(in_array($key, $uuidtypes))
				$UUIDs['uuid:'.$key] = true;
			else if(substr($key, 0, 5) == 'uuid:')
				$setUUIDs[$key] = $val;
		}
	}

	foreach($setUUIDs as $key => $val)
	{
		if(isset($UUIDs[$key]))
			unset($UUIDs[$key]);
	}

	if(count($UUIDs) <= 0)
	{
		if(count($setUUIDs))
		{
			foreach($setUUIDs as $key => $val)
				echo "$key=$val\n";
			die;
		} else
			die("Unable to add UUID to object.\n");
	}

	foreach($UUIDs as $key => $val)
	{
		$uuid = new uuid();
		$UUIDs[$key] = $uuid->v4();

		$lines[] = '<tag k="'.$key.'" v="'.$UUIDs[$key].'"/>';
	}

	$lines[] = $close;
	$lines[] = '</modify>';
	$lines[] = '</osmChange>';

	$lines = implode("\n", $lines)."\n";

	$chID = newChangeSet();

	list($start, $rest) = explode(' changeset="', $lines, 2);
	list($crud, $rest) = explode('"', $rest, 2);
	$lines = $start.' changeset="'.$chID.'" '.$rest;

	uploadChange($chID, $lines);

	foreach($UUIDs as $key => $val)
		echo "$key=$val\n";
	foreach($setUUIDs as $key => $val)
		echo "$key=$val\n";

	function newChangeSet()
	{
		global $OSMuser, $OSMpass, $server;

	        $changeset = "<osm><changeset><tag k='created_by' v='BigTinCan Upload Script' /><tag k='comment' v='Adding UUIDs to Object'/></changeset></osm>";

	        $head  = "PUT /api/0.6/changeset/create HTTP/1.1\r\n";
	        $head .= "host: $server\r\n";
	        $head .= "Authorization: Basic ".base64_encode($OSMuser.':'.$OSMpass)."\r\n";
        	$head .= "Content-Length: ".strlen($changeset)."\r\n";
	        $head .= "Connection: close\r\n\r\n".$changeset;

	        if(($fp = @fsockopen($server, 80)) === FALSE)
			die("Unable to contact OSM Server.\n");

	        fputs($fp, $head);

	        $body = false;
        	while(!feof($fp))
	        {
        	        $line = trim(fgets($fp));
                	if($line == '')
	                {
        	                $body = true;
                	        continue;
	                } else if(!$body)
        	                continue;
                	$changeid = $line;
	                break;
        	}
	        fclose($fp);

	        if(intval($changeid) != $changeid || $changeid <= 0)
			die("Failed to open new change set, error return from OSM: $changeid.\n");

		return intval($changeid);
	}

	function uploadChange($chID, $object)
	{
		global $OSMuser, $OSMpass, $server;

		$head  = "POST /api/0.6/changeset/$chID/upload HTTP/1.1\r\n";
		$head .= "host: $server\r\n";
	        $head .= "Authorization: Basic ".base64_encode($OSMuser.':'.$OSMpass)."\r\n";
	        $head .= "Content-Length: ".strlen($object)."\r\n";
	        $head .= "Content-Type: application/x-www-form-urlencoded\r\n";
	        $head .= "Connection: close\r\n\r\n".$object;

	        if(($fp = @fsockopen($server, 80)) === FALSE)
			die("Unable to contact OSM Server.\n");

	        fputs($fp, $head);
        	fflush($fp);

		$bits = explode(' ', trim(fgets($fp)), 3);

		$lines = '';
		while(!feof($fp))
			$lines .= $line = fgets($fp);

	        fclose($fp);

		if($bits['1'] != 200)
			die("Failed to upload changes\n");
	}

	class uuid
	{
		protected $uuidobject;

		protected function create()
		{
			if(!is_resource($this->uuidobject))
				uuid_create(&$this->uuidobject);
		}

		public function v4()
		{
			$this->create();
			uuid_make($this->uuidobject, UUID_MAKE_V4);
			uuid_export($this->uuidobject, UUID_FMT_STR, &$uuidstring);
			return trim($uuidstring);
		}
	}