- <?php
- /**
- * TightURL :: A blind redirection service
- *
- * Copyright (c) 2004, Ron Guerin <ron@vnetworx.net>
- * portions Copyright (c) 2002,2003 Free Software Foundation
- *
- * This file implements a blind redirection service named TightURL.
- * TightURL is Free Software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * TightURL is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * If you are not able to view the LICENSE, which should
- * always be possible within a valid and working TightURL release,
- * please write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * to get a copy of the GNU General Public License or to report a
- * possible license violation.
- *
- * @package TightURL
- * @author Ron Guerin <ron@vnetworx.net>
- * @license http://www.fsf.org/licenses/gpl.html GNU Public License
- * @copyright Copyright © 2004 Ron Guerin
- * @filesource
- * @link http://tighturl.com TightURL
- * @version 0.1
- *
- */
- /**
- * This is the TightURL release number.
- */
- define(VERSION, "0.1");
-
- /**
- * TightURL will not work with PHP versions older than this.
- */
- define(REQUIRED_PHP_VERSION, "4.3.0");
-
- // System defaults, DO NOT EDIT THIS FILE
- // Edit tighturl.config.inc.php instead!
-
-
-
- /**
- * MySQL variables
- *
- * @global string $dbhost
- */
- $dbhost = "localhost";
- /**
- * MySQL variables
- *
- * @global string $dbuser
- */
- $dbuser = "dbuser";
- /**
- * MySQL variables
- *
- * @global strgin $dbpass
- */
- $dbpass = "dbpass";
- /**
- * MySQL variables
- *
- * @global string $tighturl
- */
- $dbname = "tighturl";
- /**
- * MySQL variables
- *
- * @global string $dbtable
- */
- $dbtable = "urls";
-
- /**
- * 404-Method: TRUE or FALSE
- *
- * @global int $FOFMethod
- */
- $FOFMethod=FALSE; //0=Full URL path or mod_rewrite, 1=404-Method compressed URLs
- /**
- * Reserved URLs: TRUE or FALSE
- *
- * @global int $Reserved
- */
- $Reserved=TRUE; //0=Do not use Reserved URLs, 1=Use Reserved URLs
- // URIBL variables
-
- $uribl = array("multi.surbl.org");
- $uriblurl = array("www.surbl.org");
-
- // Text strings and style variables
- $svcname = "URLSquisher";
- $verbtext = "Squish";
- $pasttext = "Squished";
- $tagline = "Squish long URLs to make short ones";
- $headcolor = "#006600";
- $tablecolor = "#00CC99";
- $copystart = date("Y");
- $copyrightholder = "SquishURL Enterprises";
- global $copyright, $conn, $db;
-
- // Reserved URLs
- $ReservedURL = array("faq","help","code","source","docs","cvs","arch","url",
- "about","admin","setup","svn");
-
- // You REALLY don't want to edit below here unless you know what you're doing.
-
- ob_start(); // Turn on output buffering to avoid header issues
- initialize_service();
- main();
- ob_end_flush(); // Turn off output buffering, flush buffer
- exit;
-
- // *************************************************************************
-
- /**
- * Main. Process whatever the incoming request is.
- */
- function main() {
-
- global $REQUEST_URI, $FOFMethod, $uribl, $uriblrbl, $uribls;
- global $svcname, $verbtext, $pastext, $tagline,
- $headcolor, $tablecolor, $copystart, $self;
-
- echo "<html>\n";
- echo " <head>\n";
- echo " <title>".$svcname."</title>\n";
- echo " </head>\n";
- echo " <body>\n";
- if ( (isset($_REQUEST['save']) && $_REQUEST['save'] == 'yes')
- && (isset($_REQUEST['url']) && !empty($_REQUEST['url']) ) ) {
- save_URL($_REQUEST['url']);
- }
- elseif ( isset($_REQUEST['i']) && !empty($_REQUEST['i']) ) {
- lookup_ID($_REQUEST['i']);
- }
- elseif ($FOFMethod && preg_match("/^\/+([a-zA-Z0-9]+)$/",$REQUEST_URI,$matches)) {
- lookup_ID($matches[1]);
- }
- elseif ($FOFMethod && $REQUEST_URI != "/") {
- display_HTML("","Error: Couldn't find a valid ".$svcname." URI.");
- }
- else {
- display_HTML("main");
- }
- echo " </body>\n";
- echo "</html>\n";
- }
-
- function initialize_service() {
- global $validurlpattern, $validippattern, $FOFMethod, $copyright, $copystart, $uribls,
- $uribl, $uriblrbl, $self, $conn, $db;
-
- if (version_compare(phpversion(), REQUIRED_PHP_VERSION)<0) {
- die_HTML("","TightURL ".VERSION." needs PHP >= ".REQUIRED_PHP_VERSION." (you are using ".phpversion().")<br />\n");
- }
- $os=strpos(strtolower(PHP_OS), "win")===false?"nix":"win";
-
- $validurlpattern="^(http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)";
- $validurlpattern.="*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])";
- $validurlpattern.="\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)";
- $validurlpattern.="\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)";
- $validurlpattern.="\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])";
- $validurlpattern.="|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org";
- $validurlpattern.="|biz|arpa|info|name|pro|aero|coop|museum|us|ca|uk|jp|ru|ua|fr|gr|de|dk|tr|ie";
- $validurlpattern.="|it|au|br|cc|ch|cn|es|fi|gr|hk|hu|il|in|kr|mx|my|nl|no|nu|nz|ph|pl";
- $validurlpattern.="|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|aw|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm";
- $validurlpattern.="|bn|bo|bs|bt|bv|bw|by|bz|cf|cd|cg|ch|ci|ck|cl|cm|co|cr|cs|cu|cv|cx|cy|cz|dj";
- $validurlpattern.="|dm|do|dz|ec|ee|eg|eh|er|et|fj|fk|fm|fo|fx|ga|gb|gd|ge|gf|gh|gi|gl|gm|gn|gp";
- $validurlpattern.="|gq|gs|gt|gu|gw|gy|hm|hn|hr|ht|id|io|iq|ir|is|jm|jo|ke|kg|kh|ki|km|kn|kp|kw";
- $validurlpattern.="|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|mn|mo|mp|mq";
- $validurlpattern.="|mr|ms|mt|mu|mv|mw|mz|na|nc|ne|nf|ng|ni|np|nr|nt|om|pa|pe|pf|pg|pk|pm|pn|pr";
- $validurlpattern.="|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su";
- $validurlpattern.="|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|um|uy|uz|va";
- $validurlpattern.="|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zr|zw";
- $validurlpattern.="|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$";
-
- $validippattern="/^(http|https|ftp):\/\/(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])";
- $validippattern.="\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])/";
-
- if (file_exists("tighturl.config.inc.php")) { include("tighturl.config.inc.php"); }
- if ($FOFMethod) { header("HTTP/1.1 200 OK"); }
-
- // Figure out our copyright string
- $thisyear = date("Y");
- $copyright = $copystart;
- if ($copystart != $thisyear) { $copyright.="-".$thisyear; }
- for ($i=0; $i<count($uribl); $i++) {
- if ($i > 0) { $uribls.=", "; }
- $uribls.= "<a href='http://".$uriblurl[$i]."'>".$uribl[$i]."</a>";
- }
-
- // Figure out correct self
- if (strncmp($_SERVER['PHP_SELF'],$REQUEST_URI,strlen($_SERVER['PHP_SELF'])) != 0) {
- $self .="/";
- }
- else {
- $self .= $_SERVER['PHP_SELF']."/"; // We need the script name
- }
-
- // Connect to MySQL, open database.
- $conn = mysql_connect($dbhost, $dbuser, $dbpass) or die_HTML("Cannot connect to database.");
- $db = mysql_select_db($dbname, $conn) or die_HTML("Cannot select database. ".mysql_error());
- }
-
- /**
- * Windows version of the *nix-only PHP function checkdnsrr.
- */
- function wincheckdnsrr($host, $rtype = '') {
- if (!empty($host)) {
- if ($rtype == '') $rtype = "MX";
- exec("nslookup -type=$rtype $host",$result);
- foreach ($result as $line) {
- if (eregi("^$host",$line)) { return true; }
- }
- return false;
- }
- return false;
- }
-
- /**
- * addslashes wrapper to check for gpc_magic_quotes
- * @author Gavin Zuchlinski <gav@libox.net>
- */
- function nice_addslashes($string) {
- // if magic quotes is on the string is already quoted, just return it
- $magic_quotes = (bool) ini_get('magic_quotes_gpc');
- if ($magic_quotes == TRUE)
- return $string;
- else
- return addslashes($string);
- }
-
- /**
- * sanitize a string for SQL input (simple slash out quotes and slashes)
- */
- function sanitize_sql_string($string, $min='', $max='') {
- $string = nice_addslashes($string); //gz
- $pattern = "/;/"; // jp
- $replacement = "";
- $len = strlen($string);
- if((($min != '') && ($len < $min)) || (($max != '') && ($len > $max)))
- return FALSE;
- return preg_replace($pattern, $replacement, $string);
- }
-
- /**
- * Counts the number of times a substring is contained in a given string.
- */
- function countSubstrs($haystack, $needle) {
- return (($p = strpos($haystack, $needle)) === false) ? 0 : (1 + countSubstrs(substr($haystack, $p+1), $needle));
- }
-
- /**
- * Checks to see if a given URL is on a URI blacklist. Currently this means SURBL. http://www.surbl.org
- *
- * Returns TRUE if the domain is listed on any configured URIBLs.
- */
- function On_URIBL($url) {
- global $uribl, $uriblurl, $validippattern, $os;
- if ($url) {
- // Test for IP address, reverse the quads if found
- if (preg_match($validippattern,$url,$matches)) {
- $domain=$matches[5].".".$matches[4].".".$matches[3].".".$matches[2];
- }
- else {
- // strip out second-level domain name
- preg_match("|.?://(www\.)?([^/:]+)|",$url,$matches); // Needs work
- $domain = $matches[2];
- // kluge to compensate for inadequate regex above
- while (countSubstrs($domain,".") > 1) {
- $chop = strpos($domain,".");
- $domain = substr($domain,$chop + 1);
- }
- }
- // Query multi.surbl.org to see if domain/IP appears as target in known spam
- for ($i=0; $i<count($uribl); $i++) {
- if ($os == "nix") {
- $recexists = checkdnsrr($domain.".".$uribl[$i],"A");
- }
- else {
- $recexists = wincheckdnsrr($domain.".".$uribl[$i],"A");
- }
- if ($recexists) {
- $uribls.="<a href='http://".$uriblurl[$i]."'>".$uribl[$i]."</a> ";
- }
- }
- if ($uribls) { return $uribls; } else { return FALSE; }
- }
- }
-
- /**
- * Checks to see if a given URL is a Reserved URL.
- *
- * Returns TRUE if the ID is listed as a Reserved URL.
- */
- function On_Reserve($id) {
- $res=FALSE;
-
- if ($id) {
- $sexatrigesimal = base_convert($id, 10, 36);
- for ($i=0; $i<count($ReservedURL); $i++) {
- if ($sexatrigesimal == strtolower($ReservedURL[$i])) return TRUE;
- }
- return FALSE;
- }
- }
-
- /**
- * Save the given URL in the database if unique and return the ID or return an existing ID for given URL.
- * The ID returned will be a sexatrigesimal (Base-36) number.
- *
- * Saves the URL in the database, converts the decimal ID value returned by the database to
- * a sexatrigesimal value, and displays the generated TightURL.
- */
- function save_URL($url) {
- global $dbtable, $svcname, $FOFMethod, $validurlpattern, $pasttext, $self;
-
- if (file_exists("tighturl.tmpl")) $html = file_get_contents("tighturl.tmpl");
-
- if ( !ereg($validurlpattern, $url) ) {
- display_HTML("","Error: That URL is not valid.",$url,"",$url);
- }
- else {
- if ( $url != sanitize_sql_string($url, $min='', $max='')) {
- display_HTML("","Error: Bad URL.",$url,"",$url);
- }
- else {
- $lists = On_URIBL($url);
- if (! $lists) {
- $req = "SELECT * FROM $dbtable WHERE url = '$url';";
- $res = mysql_query($req)
- or die_HTML("Error: Duplicate check query failed<br />");
- if (mysql_num_rows($res) == 0) {
- do {
- $req ="INSERT INTO $dbtable (id, url) ";
- $req .= "VALUES ('', '$url');";
- if (mysql_query($req)) {
- $decimal = mysql_insert_id();
- }
- else {
- display_HTML("","Error: Database failure.");
- }
- $reserved = on_Reserve($id);
- if ($reserved) {
- // Blank out URL in record just written
- }
- while ($reserved)
- }
- else {
- // Return existing ID for this duplicate request
- $decimal = mysql_result($res, 0, "id");
- }
- $sexatrigesimal = base_convert($decimal, 10, 36);
- $address = "http://".$_SERVER['HTTP_HOST'].$self;
-
- if (! $FOFMethod) { $address .= "?i="; } // We need the parameter tag
-
- $address .= $sexatrigesimal; // Append the Base-36 ID to the URL
-
- display_HTML("save","",$url,$address);
- }
- else {
- display_HTML("","Error: Submitted URL (".$url.") is listed in ".$lists." You may not create a ".$svcname." link for it.");
- }
- }
- }
- }
-
- /**
- * Looks up given ID in the database and redirects, displays template, or
- * displays error page. Expects the ID to be a sexatrigesimal (Base-36) number,
- * which is the format used by TightURLs.
- *
- * We convert the ID to decimal before looking it up in the database, as the
- * ID field is a MySQL autoincrement decimal value.
- */
- function lookup_ID($sexatrigesimal) {
- global $dbtable, $svcname;
-
- $decimal = base_convert ($sexatrigesimal, 36, 10);
-
- $req = "SELECT * FROM $dbtable WHERE id = '$decimal';";
- $res = mysql_query($req)
- or die_HTML("Error: Query failed<br />");
-
-
-
- // Here, determine if there's a record in the DB. If yes, show it, if
- // it's not a blank URL. Otherwise if it's on the reserved list, show
- // template file. Otherwise generate error.
-
- if (On_Reserve($decimal)) {
- display_HTML($sexatrigesimal);
- }
- else {
-
-
-
- if (mysql_num_rows($res) == 0) {
- header("HTTP/1.1 404 Not Found");
- display_HTML("","Error: That ".$svcname." ID is not in our database.");
- }
- else {
- header("Location: ".mysql_result($res, 0, "url"));
- }
- }
-
- /**
- * Display HTML page using template and template variables.
- *
- * Reads in the main system template file (tighturl.tmpl) into $html .
- *
- * $template
- * Checks for the existence of a subtemplate named tighturl.$template.tmpl
- * and replaces template variable $HTML in the main template tighturl.tmpl
- * with the contents of tighturl.$template.tmpl if any.
- *
- * Then any remaining $HTML from the only or inner template is replaced by $content,
- * along with $url, $tighturl, and $input. A variety of other replacements are
- * made using various global variables.
- *
- * $content
- * HTML content to be replace template variable $HTML
- *
- * $url
- * URL submitted to TightURL
- *
- * $tighturl
- * TightURL generated for $url
- *
- * $input
- * When submitted URL does not validate it is passed back as $input
- *
- * Template variables are words in all capital letters that start with a
- * $ symbol, such as $TEMPLATEVARIABLE. TightURL now supports at least
- * 20 template variables. At runtime, these template variables are replaced
- * by program variables.
- * - $HTML : HTML passed into the function as $input by the program or an inner template
- * - $URL : URL submitted to TightURL
- * - $URLLEN : Length of the submitted URL
- * - $TIGHTURL : TightURL generated for the submitted URL
- * - $TIGHTURLLEN : Length of generated TightURL
- * - $DIFF : Difference in length between submitted and TightURLs
- * - $INPUT : Bad input URL being passed back to output form
- * - $SVCNAME : Name of the TightURL service
- * - $HEADCOLOR : Color of the H1 Header tag
- * - $TABLECOLOR : Color of the table containing URL input field
- * - $TAGLINE : Tagline of the TightURL service
- * - $CPASTTEXT : Capitalized past-tense word for tightening URLs
- * - $PASTTEXT : Non-Capitalized past-tense word for tightening URLs
- * - $CVERBTEXT : Capitalized action word for tightening URLs
- * - $VERBTEXT : Non-Capitalized action word for tightening URLs
- * - $COPYRIGHT : Copyright duration string generated from $copystart global variable,
- * will be current 4-digit year if $copystart not defined.
- * - $COPYRIGHTHOLDER : Name of copyright holder
- * - $URLBLS : HTML string of URIBLs TightURL is checking
- * - $HOST : Hostname TightURL is running on
- * - $SELF : Name TightURL is invoked as
- */
- function display_HTML ($template,$content = "",$url="",$tighturl="",$input="") {
- global $svcname, $verbtext, $pasttext, $tagline, $uribls,
- $headcolor, $tablecolor, $copyright, $copyrightholder, $self;
-
- if (file_exists("tighturl.tmpl")) {
- $html = file_get_contents("tighturl.tmpl");
- if (($template != "") && file_exists("tighturl.".$template.".tmpl")) {
- $template = file_get_contents("tighturl.".$template.".tmpl");
- $html = preg_replace("/\\\$HTML/",$template,$html);
- }
- elseif ($template != "") {
- header("HTTP/1.1 404 Not Found");
- $html = preg_replace("/\\\$HTML/","Error: Template file tighturl.".$template.".tmpl cannot be found.",$html);
- }
- if (substr($content, 0, 6) == "Error:") {
- $content = preg_replace("/Error:/","<big><font color='red'>Error:",$content)."</font></big>";
- }
- if ($content) $content.="<br />\n";
- // Always replace longer similar tokens before shorter ones. Things won't work the
- // way you expect if you replace $URL first, and then replace $URLLEN.
- $html = preg_replace("/\\\$HTML/",$content,$html);
- $html = preg_replace("/\\\$URLLEN/",strlen($url),$html);
- $html = preg_replace("/\\\$URL/",$url,$html);
- $html = preg_replace("/\\\$INPUT/",$input,$html);
- $html = preg_replace("/\\\$TIGHTURLVER/",VERSION,$html);
- $html = preg_replace("/\\\$TIGHTURLLEN/",strlen($tighturl),$html);
- $html = preg_replace("/\\\$TIGHTURL/",$tighturl,$html);
- $html = preg_replace("/\\\$DIFF/",strlen($url)-strlen($tighturl),$html);
- $html = preg_replace("/\\\$SVCNAME/",$svcname,$html);
- $html = preg_replace("/\\\$HEADCOLOR/",$headcolor,$html);
- $html = preg_replace("/\\\$TABLECOLOR/",$tablecolor,$html);
- $html = preg_replace("/\\\$TAGLINE/",$tagline,$html);
- $html = preg_replace("/\\\$CPASTTEXT/",$pasttext,$html);
- $html = preg_replace("/\\\$PASTTEXT/",strtolower($pasttext),$html);
- $html = preg_replace("/\\\$VERBTEXT/",strtolower($verbtext),$html);
- $html = preg_replace("/\\\$CVERBTEXT/",$verbtext,$html);
- $html = preg_replace("/\\\$COPYRIGHTHOLDER/",$copyrightholder,$html);
- $html = preg_replace("/\\\$COPYRIGHT/",$copyright,$html);
- $html = preg_replace("/\\\$URIBLS/",$uribls,$html);
- $html = preg_replace("/\\\$HOST/",$_SERVER['HTTP_HOST'],$html);
- $html = preg_replace("/\\\$SELF/",$self,$html);
- $html = preg_replace("/\\\$__/","$",$html); // Template Variables shown as text instead of substituted
- echo $html;
- }
- else {
- header("HTTP/1.1 404 Not Found");
- echo "<big><font color='red'>Error: TightURL Redirection service (".$svcname.") site template not found.</font></big><br />\n";
- }
- }
-
- /**
- * Die in an HTML-friendly way
- */
- function die_HTML($errmsg,$func=__FUNCTION__,$lineno=__LINE__) {
- $text="<br />Error: ".$errmsg."<br />Function: ".$func."<br />Line: ".$lineno."</body></html>";
- die;
- }
- ?>