Showing posts with label network. Show all posts
Showing posts with label network. Show all posts

Wednesday, January 26, 2011

Simple URL Shortening Script

If you're running Apache and are able to use the mod_asis module, it's very easy to setup a simple and efficient URL shortener. This URL shortening script doesn't require any sort of database and it doesn't have the overhead of something like PHP added to every single redirection.

If you read the documentation for mod_asis, the fundamentals of how this all works may be immediately obvious. If not, basically mod_asis lets you have a sort of static response cache. A lot like having a static HTML cache, but with HTTP headers.

Assuming you have your URL shortening domain setup and you have a nice empty DocumentRoot for your new URL shortening service, the first thing you need to do is create a directory named "stubs". If you want to setup some sort of UI to create new shortened URLs with setup your permissions on stubs so that PHP can write to stubs, but nobody else can.

Within the stubs directory create an htaccess file (ideally you'd use Directory or Location containers in your VirtualHost, but for example sake I'm using htaccess).
Within that htaccess file, add the fillowing line.

SetHandler send-as-is


What that line does, is force every requested file to pass through mod_asis, which if you've read the documentation for mod_asis you know that other than adding a Date and Server header to the response, mod_asis just sends the file to the visitor as-is.

So, if I put a file in that directory named "abc123" with the following contents, I'll basically be given a 302 redirect from the server pointing me to google.com

NOTE: There are two newlines after the Location line to signal the end of HTTP headers. This is important

Status: 302
Location: http://www.google.com/



So basically, at this point I could distribule the shortened URL "http://domain/stubs/abc123" and it would redirect visitors to google.com; This isn't all that nice though, as I have "stubs" in the URL and that sort of defeats the purpose of a shortened URL.

That's why in the parent directory of stubs, AKA the DocumentRoot, I add the following to the htaccess file.

RewriteEngine on
RewriteBase /
RewriteRule ([a-f\d]{1,8})$ stubs/$1 [L]


Now I can distribute my shortened URL as "http://domain/abc123" and it will redirect to google.com; I could still distribute the URL with stubs in it if I wanted and it would still work for both shortened URLs.

At this point I have a small, simple, and efficient URL shortener. I have to manually go into my stubs directory and add a new file every time I want to shorten a URL though.

For that, I have the following simple PHP script with a bulk shortened URL capable UI.

<!doctype html>  
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>My URL Shortener</title>
</head>

<body>
<div id="container">
<header>
<h1>My URL Shortener</h1>
<p>Enter as many URLs as you want, one per line.</p>
</header>
<div id="main">
<?php
/*
Contains backwards compatibility code;
If you comment this include() out and don't get any errors, it's safe to leave it out.
*/
include('./lib.php');

if( ! empty($_POST['u']))
{
$url_list = '<ul>';
foreach(preg_split('#[\r\n\f]+#', $_POST['u'], -1, PREG_SPLIT_NO_EMPTY) as $_url)
{
$url = parse_url($_url);
if($url && http_build_url('', $url) == $_url)
{
$crc = sprintf('%x', crc32($_url));
if( ! file_exists("./stubs/{$crc}"))
{
file_put_contents("./stubs/{$crc}", "Status: 302\nLocation: {$_url}\n\n\n");
}
printf('<li><a href="http://%1$s%2$s%3$s">http://%1$s%2$s%3$s</a> » %4$s</li>',
$_SERVER['HTTP_HOST'],
str_replace('//', '/', dirname($_SERVER['REQUEST_URI']) . '/'),
$crc,
$_url
);
}
}
if(strlen($url_list) > 4)
{
echo $url_list, '</ul>';
}
}
?>
<form action="index.php" method="post">
<fieldset>
<legend>URL</legend>
<textarea name="u" id="u" rows="10" style="width:400px;"></textarea>
<p><input type="submit" name="s" id="s" value="Shorten!"/></p>
</fieldset>
</form>
</div>
<footer>© Me; 2011</footer>
</div>
</body>
</html>


Also, because the PHP function "http_build_url" is a PECL function, I have the following code I include in "lib.php".

<?php
if (!function_exists('http_build_url'))
{
define('HTTP_URL_REPLACE', 1); // Replace every part of the first URL when there's one of the second URL
define('HTTP_URL_JOIN_PATH', 2); // Join relative paths
define('HTTP_URL_JOIN_QUERY', 4); // Join query strings
define('HTTP_URL_STRIP_USER', 8); // Strip any user authentication information
define('HTTP_URL_STRIP_PASS', 16); // Strip any password authentication information
define('HTTP_URL_STRIP_AUTH', 32); // Strip any authentication information
define('HTTP_URL_STRIP_PORT', 64); // Strip explicit port numbers
define('HTTP_URL_STRIP_PATH', 128); // Strip complete path
define('HTTP_URL_STRIP_QUERY', 256); // Strip query string
define('HTTP_URL_STRIP_FRAGMENT', 512); // Strip any fragments (#identifier)
define('HTTP_URL_STRIP_ALL', 1024); // Strip anything but scheme and host

// Build an URL
// The parts of the second URL will be merged into the first according to the flags argument.
//
// @param mixed (Part(s) of) an URL in form of a string or associative array like parse_url() returns
// @param mixed Same as the first argument
// @param int A bitmask of binary or'ed HTTP_URL constants (Optional)HTTP_URL_REPLACE is the default
// @param array If set, it will be filled with the parts of the composed url like parse_url() would return
function http_build_url($url, $parts=array(), $flags=HTTP_URL_REPLACE, &$new_url=false)
{
$keys = array('user','pass','port','path','query','fragment');

// HTTP_URL_STRIP_ALL becomes all the HTTP_URL_STRIP_Xs
if ($flags & HTTP_URL_STRIP_ALL)
{
$flags |= HTTP_URL_STRIP_USER;
$flags |= HTTP_URL_STRIP_PASS;
$flags |= HTTP_URL_STRIP_PORT;
$flags |= HTTP_URL_STRIP_PATH;
$flags |= HTTP_URL_STRIP_QUERY;
$flags |= HTTP_URL_STRIP_FRAGMENT;
}
// HTTP_URL_STRIP_AUTH becomes HTTP_URL_STRIP_USER and HTTP_URL_STRIP_PASS
else if ($flags & HTTP_URL_STRIP_AUTH)
{
$flags |= HTTP_URL_STRIP_USER;
$flags |= HTTP_URL_STRIP_PASS;
}

// Parse the original URL
$parse_url = parse_url($url);

// Scheme and Host are always replaced
if (isset($parts['scheme']))
$parse_url['scheme'] = $parts['scheme'];
if (isset($parts['host']))
$parse_url['host'] = $parts['host'];

// (If applicable) Replace the original URL with it's new parts
if ($flags & HTTP_URL_REPLACE)
{
foreach ($keys as $key)
{
if (isset($parts[$key]))
$parse_url[$key] = $parts[$key];
}
}
else
{
// Join the original URL path with the new path
if (isset($parts['path']) && ($flags & HTTP_URL_JOIN_PATH))
{
if (isset($parse_url['path']))
$parse_url['path'] = rtrim(str_replace(basename($parse_url['path']), '', $parse_url['path']), '/') . '/' . ltrim($parts['path'], '/');
else
$parse_url['path'] = $parts['path'];
}

// Join the original query string with the new query string
if (isset($parts['query']) && ($flags & HTTP_URL_JOIN_QUERY))
{
if (isset($parse_url['query']))
$parse_url['query'] .= '&' . $parts['query'];
else
$parse_url['query'] = $parts['query'];
}
}

// Strips all the applicable sections of the URL
// Note: Scheme and Host are never stripped
foreach ($keys as $key)
{
if ($flags & (int)constant('HTTP_URL_STRIP_' . strtoupper($key)))
unset($parse_url[$key]);
}


$new_url = $parse_url;

return
((isset($parse_url['scheme'])) ? $parse_url['scheme'] . '://' : '')
.((isset($parse_url['user'])) ? $parse_url['user'] . ((isset($parse_url['pass'])) ? ':' . $parse_url['pass'] : '') .'@' : '')
.((isset($parse_url['host'])) ? $parse_url['host'] : '')
.((isset($parse_url['port'])) ? ':' . $parse_url['port'] : '')
.((isset($parse_url['path'])) ? $parse_url['path'] : '')
.((isset($parse_url['query'])) ? '?' . $parse_url['query'] : '')
.((isset($parse_url['fragment'])) ? '#' . $parse_url['fragment'] : '')
;
}
}
?>


That just gives me a simple textarea that I can enter a list of URLs into, and automatically have stubs for short URLs written to the stubs directory and get a list of shortened URLs back.

Monday, August 17, 2009

Putty Ubuntu SSH Autologin

With the addition of a Windows Vista computer to my small network I find myself needing to get into the Ubuntu systems via SSH when I'm on the Vista computer. This is simple with Putty, but entering my username and password every time is annoying.

I've already setup the rest of the systems on my network to have Ubuntu login to SSH automatically. I don't see why I can't have the Windows Vista computer do the same with Putty.

Having already setup the other systems, I knew I needed a key to add to the authorized_keys file on the remote system, and by looking at Putty I knew I needed a private key file.

I tried using ssh-keygen on the Ubuntu system to generate keys, but the format used for the private key was different looking than the file format of the PPK file Putty was looking for.

In order to get the key pairs I needed a tiny utility called puttygen from the Putty downloads page.


Here is what the interface looked like. I left everything default and clicked Generate.

After moving my mouse around to generate randomness while it generated a new pair of keys I clicked the Save Private Key button, selected yes when asked if I wanted to save the key without a passphrase, then selected the place I wanted to store the PPK file.

Next I copy and pasted the public key from the text area that showed up above the buttons and below where it says Public key for pasting into OpenSSH authorized_keys file, into my authorized_keys file on the remote system via nano in an open SSH session.

After closing Puttygen I closed my existing SSH session out and re-opened Putty to be presented with the settings dialog.


I entered my username in the Connection -> Data -> Autologin Username field as shown here.

Then I selected the PPK file I saved earlier in the Connection -> SSH -> Auth screen.

Viola! Autologin to Ubuntu via SSH using Putty worked like a charm.

Wednesday, May 13, 2009

Ubuntu SSH Autologin

Are you looking for Putty Ubuntu SSH Autologin ?


I've got a small network of Ubuntu computers at home and only one has a monitor. The rest I manage with SSH, FTP, and XDMCP logins.

Entering my password every time I want to get a terminal for one of the remote systems isn't very fun because my passwords are upwards of 16 characters. So I needed a way to login with SSH without needing to type a password.

On my main system, the one with the monitor, I used ssh-keygen at the terminal to generate a pair of public and private keys. By default ssh-keygen wants to create key files named id_rsa and id_rsa.pub but I decided to use home-network for my key files instead so I know what these ones are for.

I also just pressed enter for the passwords to leave them blank.

user@main-computer:~/Desktop$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa): /home/user/.ssh/home-network
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/home-network.
Your public key has been saved in /home/user/.ssh/home-network.pub.
The key fingerprint is:
00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 user@main-computer
The key's randomart image is:
+--[ RSA 2048]----+
| |
+-----------------+
user@main-computer:~/Desktop$


Once that was done I opened my FTP application and navigated the local and remote file lists to the following directory.

/home/user/.ssh/


I uploaded home-network.pub to the remote system and renamed it to authorized_keys so that on the remote system I had the following.

/home/user/.ssh/authorized_keys


If that file already existed on the remote system, I would have opened both files in my text editor and copied the contents of the *.pub file into that authorized_keys file.

Once everything was saved and uploaded I fired up SSH to login to the remote system and was logged in without needing to enter my password.

Thursday, June 26, 2008

SMS/Email Domains for U.S. Cellular Providers

I often see people asking how to send SMS messages from their website. Well, you can do so through your SMTP server or if you're using some other type of email system, for instance Postfix on Debian, you can use that too.

You send the message/email just like you would any other email, you just have to direct it to the address the service provider has setup to recieve messages.

In most cases this is the cellphones ten digit number @ provider-address dot com.
Below is a list of common U.S. service providers and the domain they have setup to recieve SMS messages via email protocols.

CarrierDomain Pattern
AirTouch Cellular 10digitphonenumber@airtouchpaging.com
Alltel 10digitphonenumber@alltelmessage.com
Ameritech Cellular 10digitphonenumber@paging.acswireless.com
AT&T Wireless 10digitphonenumber@mobile.att.net
Bell Atlantic 10digitphonenumber@message.bam.com
BellSouth 10digitphonenumber@wireless.bellsouth.com
Cellular One Not available from carrier
Cingular Wireless 10digitnumber@mobile.mywireless.com
Comcast Cellular 10digitphonenumber@cellularone.tstmsg.com
GTE Wireless 10digitphonenumber@messagealert.com
Nextel 10digitphonenumber@page.nextel.com
Omnipoint 10digitphonenumber@omnipointpcs.com
Pacific/Nevada Bell 1+10digitphonenumber@pacbellpcs.com
PrimeCo 10digitphonenumber@primeco.textmessage.com
Southwestern Bell 10digitphonenumber@email.swbw.com
Sprint 10digitphonenumber@messaging.sprintpcs.com
Suncom 10digitphonenumber@mobile.att.net
TMobile 10digitphonenumber@tmomail.net
Telecorp 10digitphonenumber@mobile.att.net
Tritel 10digitphonenumber@mobile.att.net
Triton PCS 10digitphonenumber@mobile.att.net
U.S. West 10digitphonenumber@uswestdatamail.com
Verizon 10digitphoneumber@msg.myvzw.com
Voicestream 10digitphonenumber@voicestream.net
Boost Mobile 10digitphonenumber@myboostmobile.com


Google is able to look these up just by having the number somehow, I'd really like to know where's they're getting it from.