loading...

Writing a Link Shortener with PHP and Airtable

eruizdechavez profile image Erick Ruiz de Chavez ・4 min read

If you prefer JavaScript πŸ€“, I also have a Node.js version of this project πŸŽ‰., I'll publish its post soon, so stay tuned.

What you'll get

A custom URL shortener with your own domain πŸŽ‰.

What you'll need

  • A server with Apache and PHP.
  • An Airtable account.

Some background

Over the weekend I was working on a small side project for a meetup I started attending to a few weeks ago. I am printing a QR code (with a link) for a small flyer and adding an NFC tag (with the same link) to it as well. All of the sudden I was thinking πŸ€” I need a practical way to update a my link without having to print again my QR code and reprogram the NFC tag.

My initial thinking was to just use one of the many services out there but then I thought why not build a really simple one so I can update it as I need?, I also wanted to have a quick way of updating it without having to republish the code, or jumping into an ssh session to change some file on a server.

The answer πŸ’‘ I came up was to write a pretty small, yet effective, PHP script that gets an ID, fetches the real link from Airtable, and ends up redirecting the browser to the real link.

To make it look fancier, I used Apache's mod_rewrite so I get a clean URL, but it is really not required.

How to put everything together

We start by preparing Airtable. If you do not have an account, get one, it is free and really useful. Once you are ready with your account, you can copy my Base into your account. This will save us some time and will allow you to familiarize yourself with Airtable at your own pace. The table has some fields, but the important ones are ID and URL. ID is using Airtable's record ID (removing the letters rec from the beginning) and URL is a string with your URL.

After you are ready with your Base and Table, you need to get your Base ID and API Token. To get the Base ID go to https://airtable.com/api, click on your base name and you should see an API explorer with the ID of your base in the first paragraphs of the Introduction. To get your API Token go to https://airtable.com/account and you should have an obfuscated field in the API section, to get the token just click on it and it will reveal the token. I am assuming you copied my base so I'll assume your Table name is the same as mine (if not, you can change the name on the config.ini file).

With this 3 pieces of information we are ready to get some magic done πŸ§™πŸ»β€β™‚οΈ. We'll start by adding a folder on our web server; since it is a link "shortener" it made sense to me to create a folder named s. Inside this folder I have the following files:

.htaccess

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !index.php
RewriteRule .* index.php?id=$0 [QSA,L]
Enter fullscreen mode Exit fullscreen mode

index.php

<?php
$config = parse_ini_file('config.ini');
$id = $_GET['id'];
$request_url = 'https://api.airtable.com/v0/' . $config['base_id'] . '/' . urlencode($config['table_name']) . '/rec' . $id;

$options = [
  'http' => [
    'method' => 'GET',
    'header' =>
      'Authorization: Bearer ' . $config['token'] . "\r\n",
  ],
];
$context = stream_context_create($options);

$response = file_get_contents($request_url, false, $context);
$record = json_decode($response, true);
$url = $record['fields']['URL'];

if ($_GET['debug']) {
  echo '<pre>';
  var_dump($options);
  var_dump($response);
  var_dump($record);
  var_dump($url);
  echo '</pre>';
} else {
  header("location: ${url}");
}
Enter fullscreen mode Exit fullscreen mode

config.ini

base_id=your-airtable-base-id-here
table_name=Your Table Name
token=your-api-token-here
Enter fullscreen mode Exit fullscreen mode

Once these 3 files are in place, there is not much else to do. We just need to have at least a link in the base, copy the ID and use it in our browser using the correct domain and path to your server. In this example, our server domain is example.com and our s folder is in the root of the public folder, so we could try going to http://example.com/s/SOMEID (assuming also that SOMEID is a valid ID in our table) and get redirected to the real URL πŸ’₯.

If for some reason I need to debug πŸ› the code and see what is going on, I can add ?debug=true to the URL and the script will show me some variables instead of doing the redirect.

There you go! A custom link shortener with very few code and you can also change the URL whenever you need.

Pending items

Airtable allows you to do 5 requests per second, so you might need to use a different storage if you are thinking to go to production with this code (which I do not recommend for big or heavy usage).

There is no error handling at all, nor logging, so again you need to think twice before going to production with this code πŸ˜‰.

Closing thoughts

I still like PHP a lot for small and quick solutions like this. I it very simple to get it up and running and I do not need to setup any monitor or daemon to keep my process running as I would need to do with Node.js.

Airtable is also a very nice tool I use pretty often both from the Web UI and programatically.

I hope you like and find this example useful. If so, please leave a comment and share with it with your friends πŸ™‚.

Discussion

pic
Editor guide
Collapse
nathanpuls profile image
nathanpuls

Erick,
Thanks for the help! Your suggestions worked. Do you know any way to make the short links work with custom urls instead of IDs on airtable? Also, I'd be very interested in your Node JS shortener (ideally with custom slugs!)

Thanks again!
Nathan

Collapse
eruizdechavez profile image
Erick Ruiz de Chavez Author

I've been a bit busy, but have not forget about this.

While I get a code I can share with you, the idea behind it is to ask Airtable to list records and use the query parameter filterByFormula where you can provide a filter. This way, assuming you have a column with unique values (your custom short links) you can use that to "list" and get an array with a single value.

I would love to give you a direct link to the API docs but Airtable's documentation customizes such links with your base ids. What you can do is go to airtable.com/api click on any of your bases, then click on the table name on the side bar, and finally click on "List records".

Collapse
nathanpuls profile image
nathanpuls

That kind of went over my head. But I'm going to keep working on url forwarding bit by bit as I have time. Again, the Node JS custom url shortener is what I'll try to be building in the end.

Collapse
eruizdechavez profile image
Erick Ruiz de Chavez Author

Thanks for the help! Your suggestions worked.

I’m glad to know they did!


Do you know any way to make the short links work with custom urls instead of IDs on airtable?

As a matter of fact, I do, that’s what I personally use 😎. Let me do some basic cleanup on that code and I can share it with you too.


Also, I'd be very interested in your Node JS shortener (ideally with custom slugs!)

Unfortunately this one is outdated and I don’t think I finished implementing the custom slug, but you should be able to adapt the PHP version pretty easily (if not, just let me know and I can also give you some hints)

Collapse
nathanpuls profile image
nathanpuls

Hey Erick,

Cool article.
I tried setting this up but I think I'm missing something. Here's a link to screenshots in my google photos album: wyr.es/airtableshortlinks

Alternatively here's the direct Google photo album: photos.app.goo.gl/w9mqAEYrkiWGJKXc7

It has the private API information but I'll just regenerate that later.

The screenshot for config.ini has a typo at the end of the table_name, I fixed that and it still wasn't working.

Thanks!
Nate

Collapse
eruizdechavez profile image
Erick Ruiz de Chavez Author

Hi @nathanpuls πŸ‘‹πŸ»!

Thanks for taking the time to read my post and try it by yourself.

After looking at your images I see where the problem is: table_name has the name of your Base (fwdshort) instead of the Table name (Links). This script does not need the name of your Base because you are already providing the Base ID as the first config value (base_id).

Give this a try and let me know if if helps πŸ‘πŸ»

Collapse
eruizdechavez profile image
Erick Ruiz de Chavez Author

I also just noticed on another of your screenshots the array keys in $request_url are changed, but they are not supposed to be changed; keep the variables as $config[β€˜base_id’] and $config[β€˜table_name’].

Collapse
w3gaucho profile image
W3G

nice work. I still didn't know airtable.com, thanks for sharing.

Collapse
eruizdechavez profile image
Erick Ruiz de Chavez Author

Thanks! It is a very nice tool, highly recommended even if all you do is use their UI.

Collapse
nathanpuls profile image
nathanpuls

I'm pretty new to coding so im not sure id be able to adapt from php to js. But the code im trying to breakdown is onurl.now.sh - it has a link to the github

Collapse
eruizdechavez profile image
Erick Ruiz de Chavez Author

Now I get why my last response "went over your head", you are not using Airtable, you are using MongoDB!

The basic idea is to have at the very minimum 3 fields on each record, 1 unique id (ObjectID works fine, but more to discuss about it), 1 URL, and 1 optional custom alias.

When someone shortens a URL, you should search if the same URL is already saved, if so, return the existing ID (or alias), if not, create one and return it.

MongoDB’s Object IDs are unique across all Data Base, so you should not have to worry about uniqueness, but they are pretty long, so you could use a randon ID instead and then encode it as base36, that way you can really have shorter URLs. Do not generate the number by just using Mand.random() that is very likely to get you collisions, a good option is to use a timestamp including milliseconds as it is very hard to get millisecond collisions (unless you are getting A LOT of new ids from A LOT of different places).