Short URL Registry

From Second Life Wiki
Jump to: navigation, search

Created by Kira Komarov.

Web-Related Derivation Tree

Movement-Related Integration Tree

ShortNote

Frequently one needs to register an URL with a database so it contains a pointer to the Linden provided URL. This has been done before with Permanent Primitive URL as well as in several projects such as Population Genetics and Selection. We expand the concept so that it uses a third-party hosted database.

Requirements

  • SQLite database on a webserver using the database structure below.
  • The LSL component below that registers a custom short URL.
  • The PHP script that handles the insert and retrieve from the SQLite database.

Both the LSL component and the PHP script share a common secret: the API key which can be generated using uuidgen or by simply entering any secret string. We use UUIDs to generate a secret since the output is hard to predict however the API key may just as well be any string.

Database

The database structure is given by the following dump:

BEGIN TRANSACTION;
CREATE TABLE "url_table" (
	 "llURL" text NOT NULL,
	 "shortURL" text NOT NULL,
	PRIMARY KEY("shortURL")
);

Code: [K] REG URL

This LSL script registers an URL with the PHP script.

<lsl> ////////////////////////////////////////////////////////// // [K] Kira Komarov - 2011, License: GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html // // for legal details, rights of fair usage and // // the disclaimer and warranty conditions. // //////////////////////////////////////////////////////////

////////////////////////////////////////////////////////// // CONFIGURATION // ////////////////////////////////////////////////////////// string SHORT_URL = "sales"; string API_KEY = "A1364788-B702-4413-B937-7A57E32B43CE"; ////////////////////////////////////////////////////////// // INTERNALS // //////////////////////////////////////////////////////////

key uReq = NULL_KEY; string llURL = "";

default {

   state_entry() {
       llReleaseURL(llURL);
       llURL = "";
       llSetTimerEvent(5);
       llRequestURL();
   }
   on_rez(integer param) {
       llReleaseURL(llURL);
       llResetScript();
   }
   timer() {
       if(llURL != "") {
           llSetTimerEvent(0);
           uReq = llHTTPRequest("http://was.fm/SIM/registerURL.php?action=register&apiKey=" + API_KEY + "&shortURL=" + SHORT_URL + "&llURL=" + llURL, [HTTP_METHOD, "GET"], "");
           return;
       }
   }
   http_request(key id, string method, string body) {
       if (method == URL_REQUEST_GRANTED) {
           llURL = body;
           return;
       }

       if(method == URL_REQUEST_DENIED) {
           llReleaseURL(llURL);
           llResetScript();
           return;
       }
   }
   http_response(key reqID, integer status, list metadata, string body) {
       if (uReq == reqID && body == SHORT_URL) {
           llHTTPResponse(uReq, 200, "OK");
           state registered;
       }
   }

}

state registered {

   state_entry() {
       llSetTimerEvent(60);
       llOwnerSay("[K] REG URL: URL registered: " + llURL);
   }
   
   timer() {
       llSetTimerEvent(0);
       uReq = llHTTPRequest(llURL, [HTTP_METHOD, "POST"], "STATUS");
   }
   
   http_request(key id, string method, string body) {
       // alarm
       if(method == "POST" && body == "STATUS") {
           llHTTPResponse(id, 200, "");
           llSetTimerEvent(60);
           return;
       }
       llOwnerSay("[K] REG URL: Requesting URL.");
       llReleaseURL(llURL);
       llResetScript();
   }
   
   changed(integer change) {
       llOwnerSay("[K] REG URL: Requesting URL.");
       llReleaseURL(llURL);
       llResetScript();
   }

}

</lsl>

Code: [K] RET URL

This LSL script retrieves an URL from the PHP script.

<lsl> ////////////////////////////////////////////////////////// // [K] Kira Komarov - 2011, License: GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html // // for legal details, rights of fair usage and // // the disclaimer and warranty conditions. // //////////////////////////////////////////////////////////

////////////////////////////////////////////////////////// // CONFIGURATION // ////////////////////////////////////////////////////////// string SHORT_URL = "sales"; string API_KEY = "A1364788-B702-4413-B937-7A57E32B43CE"; ////////////////////////////////////////////////////////// // INTERNALS // //////////////////////////////////////////////////////////

key uReq = NULL_KEY; string llURL = "";

default {

   state_entry() {
       uReq = llHTTPRequest("http://was.fm/SIM/registerURL.php?action=retrieve&apiKey=" + API_KEY + "&shortURL=" + SHORT_URL, [HTTP_METHOD, "GET"], "");
       return;
   }
   http_response(key reqID, integer status, list metadata, string body) {
       if (uReq == reqID) {
           llHTTPResponse(uReq, 200, "OK");
           llURL=body;
           state retrieved;
       }
   }

}

state retrieved {

   state_entry() {
       llOwnerSay("URL is: " + llURL);
   }

}

</lsl>

Code: PHP

Implemented actions:

  • register - register a map between a short URL and a Linden-like URL.
  • retrieve - retrieve a Linden URL based on a short URL.
<?php

	//////////////////////////////////////////////////////////
	// [K] Kira Komarov - 2012, License: GPLv3              //
	// Please see: http://www.gnu.org/licenses/gpl.html     //
	// for legal details, rights of fair usage and          //
	// the disclaimer and warranty conditions.              //
	//////////////////////////////////////////////////////////
	
	// For privacy, you need to generate a password. You can do that
	// by issuing the following command on an *nix-like system and 
	// replace "super-duper secret password" with a secret shared between
	// this PHP script and the LSL counterpart:
	// sh$ echo "super-duper secret password" | sha1sum  | awk '{ print $1 }'
	$apiKey = 'A1364788-B702-4413-B937-7A57E32B43CE';

	if(!isset($_GET['apiKey']) || $_GET['apiKey'] != $apiKey) {
		throw new Exception('Invalid API key.');
		return;		
	}
	if(!isset($_GET['action'])) {
		throw new Exception('No action specified.');
		return;
	}
	switch($_GET['action']) {
		case "register":
			if(!isset($_GET['llURL']) && !isset($_GET['shortURL'])) return;
			$llURL = $_GET['llURL'];
			$shortURL = $_GET['shortURL'];
			$db = new PDO('sqlite:customURL.sqlite');
			$q = $db->prepare("REPLACE INTO url_table(llURL, shortURL) VALUES(:llURL, :shortURL)");
			try {
				$q->execute(array(':llURL' => $llURL, ':shortURL' => $shortURL));
			}
			catch(PDOException $e) {
				die($e->getMessage());
			}
			print $shortURL;
			break;
		case "retrieve":
			if(!isset($_GET['shortURL'])) return;
			$shortURL = $_GET['shortURL'];
			$db = new PDO('sqlite:customURL.sqlite');
			$q = $db->prepare("SELECT llURL FROM url_table WHERE shortURL=:shortURL LIMIT 1");
			try {
				$q->execute(array(':shortURL' => $shortURL));
				$res = $q->fetch(PDO::FETCH_OBJ); 
			}
			catch(PDOException $e) {
				die($e->getMessage());
			}
			print $res->llURL;
			break;
		default:
			break;
	}
?>