Crea tu propio acortador de enlaces con API en PHP y Mysql

tabla de links

Un acortador de enlaces es una herramienta que permite de enviar direcciones de webs a través de las redes sociales ahorrando espacio en el mensaje. Se popularizaron mucho con twitter ya que solo se dispone de 140 caracteres por mensaje.

Hay muchísimos acortadores de url en internet, algunos son bit.ly, tinyurl, goo.gl, …

¿Porque tener un acortador de urls propio?

Por independencia sobre todo, ¿que pasaría si [pon aquí tu acortador de urls preferido] le diera por poner publicidad antes de ir a la pagina de destino? ¿y si tu quieres poner publicidad? ¿y si no te fías de las estadísticas que te dá o de como las calcula?

Pero lo que realmente me convenció a hacerlo: ¿realmente para una redirección necesito usar un servicio externo? Quiero decir: ¿que valor añadido saco de tener bit.ly/aAaAaA comparado con link.xhiena.net/aAaAaA o xhiena.net/link/aAaAaA?

A parte de que es mas corto no saco nada más, pero sinceramente, link.xhiena.net/aAaAaA es mas corto que xhiena.net/index/crea-tu-propio-acortador-de-enlaces-con-api-en-php-y-mysql

Pensando el sistema

Un pequeño resumen general de lo que debe hacer:

  • Mi sistema acortador de enlaces va a recibir una url y la va a codificar en un código de 6 caracteres.
  • El código estará compuesto por minúsculas, mayúsculas, números, ‘_’ y ‘-‘.
  • Los caracteres se podrán repetir, es decir, el código ‘——‘ será feo, pero válido.
  • Tendrá una API para poder añadir enlaces desde otras aplicaciones.
  • Dibujo de como funcionará:

    funcionamiento del acortador de urls

Es un sistema muy simple, por lo que solo crearé un diagrama simple de flujo de datos

Flujo de datos de Add

Flujo de datos de Add

Entendiendo mi código

Cada uno tenemos una forma de programar, yo suelo crearme una carpeta “includes” en la que meto todos los archivos con la conexión a la base de datos, idiomas, sesiones, … y me creo un top.php que incluye todo asi que:

require("include/top.php");

Crea una sesión, crea la conexión a la base de datos, incluye el archivo de idiomas, incluye el archivo de funciones, …

Definiendo el sistema

Base de datos

Esta es una versión mínima de un acortador de urls, así que  solo tendrá una tabla

tabla de links

tabla de links

Add.php

El sistema realmente solo tiene un proceso, que es el generar el código y guardarlo en la base de datos (que en un alarde de originalidad he llamado: ADD)

Add tiene que:

  1. Recoger variables
  2. Generar el código único
  3. Guardarlo todo en la base de datos
<?php
require("include/top.php");
$u_sql=urldecode($_GET['u']);
$formatos_return=Array("html","xml","json","txt");
$r=isset($_GET["r"])?($_GET['r']):($formatos_return[0]);
$r=(in_array($r,$formatos_return))?($r):($formatos_return[0]);
$u=addUrl($u_sql);
if ($u){
header("location: /added/".$r."/".$u);
}
?>

funciones.php

El archivo que tiene todas las funciones

/**
* Entrada: url a codificar
* Salida: el código único o false
*/
function addUrl($url){
    global $db;
    if (!checkUrl($url)){
        echo TXT_ERROR_URL_FORMAT;
        return false;
    }
    $code=getCode();
    $sql="insert into link values ('','$url','$code','0')";
    if($db->query($sql)){
        return $code;
    }
    else{
        echo $db->error;
        return false;
    }
}

Comprueba la url, genera un código y lo mete en la base de datos, poco más que explicar

/**
* entrada: url
* salida: true o false
*/
function checkUrl($url){
    //return preg_match('|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i', $url);
    return true;
}

Por ahora devuelve siempre true a expensas de mejorar la expresión regular para que pille todas las url, ya que las que tienen símbolos raros no pasan este test

/**
* entrada: nada
* salida: código
*/
function getCode(){
    $cadena_base="abcdefghijklmnopkrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-";
    $i=0;
    $c="";
    while ($i<6){
        $c.=$cadena_base[rand(0,strlen($cadena_base)-1)];
        $i++;
    }
    if (getUrl($c)!=false){
        return getCode();
    }
    else return $c;
}

En base a nuestra especificación del código, se genera un código de 6 caracteres compuesto por minúsculas, mayúsculas, números, ‘_’ y ‘-‘. getUrl devuelve false si no existe el código así que si no devuelve false, existe el código, así que se genera de nuevo.

/**
* entrada: codigo
* salida: url o false
/*
function getUrl($code){
    global $db;
    $sql="select url from link where shortcode like '$code'";
    $result=$db->query($sql);
    if ($result!=false){
        $row = $result->fetch_object();
         if ($row){
           return $row->url;
         }
         else{
             return false;
         }
    }
    else{
        return false;
    }

}

Busca el código en la base de datos y devuelve la url o false si no existe.

added.php

La pagina para mostrar el código generado:

        require("include/top.php");
        $r=isset($_GET["r"])?($_GET['r']):("html");
        switch ($r){
            default:
            case "html":
                 echo TXT_ADDED.": ".BASE_LINK_URL."".$_GET['code'];
                break;
            case "xml":
                echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<response>\n    <data>".BASE_LINK_URL."".$_GET['code']."</data>\n</response>";
                break;
            case "json":
                echo "{data : \"".BASE_LINK_URL."".$_GET['code']."\"}";
                break;
            case "txt":
                echo BASE_LINK_URL.$_GET['code'];
                break;
        }

He elegido tener 4 formatos de salida: html, xml, json y txt.

Con estas funciones ya tenemos todo el sistema. podemos añadir enlaces y con getUrl($code) podemos recuperar una dirección web guardada:

go.php

 require("include/top.php");
$u_sql=$db->real_escape_string($_GET['u']);
$u=getUrl($u_sql);
if ($u){
addVisit($u_sql);
header("location: ".$u);
}

addVisit($code) simplemente incrementa el campo visited:

function addVisit($code){
global $db;
$sql="Update link set visited=visited+1 where shortcode like '$code'";
$result=$db->query($sql);
return $result;
}

Recapitulamos lo que tenemos hasta ahora

Tenemos el sistema completo:  una página que añade una url a la base de datos: add.php y otra que va a la url pasandole el codigo.

es decir: add.php?u=http://xhiena.net&r=xml devuelve:

<?xml version="1.0" encoding="UTF-8"?>
<response>
    <data>http://xxxxxxxx.xhiena.net/yyyyyy</data>
</response>

add.php?u=http://xhiena.net&r=html en modo pagina web, add.php?u=http://xhiena.net&r=txt solo el enlace generado y add.php?u=http://xhiena.net&r=json en formato json.

y si vamos a http://xxxxxxxx.xhiena.net/go.php?u=yyyyyy nos redireccionará a xhiena.net :D

Haciéndolo bonito

Para acortar mas la url vamos a usar htaccess y rewriterule:

#si llegan 6 caracteres con minusculas, mayusculas, numeros, '_' o '-' nos vamos a go.php
RewriteRule ^([0-9a-zA-Z_-]{6})$ go.php?u=$1 [L]
#esta es solo para hacer mas bonita la url del added.php
#lo que hace es que convierte xxx.xhiena.net/html/xxxxxx en added.php?code=xxxxxx&r=html
RewriteRule ^added/([a-zA-Z]+)/([0-9a-zA-Z_-]{6})$ added.php?code=$2&r=$1 [L]

y ya lo tenemos!

El api

el api ya esta hecho!! al hacer add.php por get lo podemos llamar directamente :D

Aunque si quieres algo mas bonito, puedes añadir al htaccess:

RewriteRule ^api/add/([a-zA-Z]+)/(/+)$ add.php?u=$2&r=$1 [L]

Os imagináis que hace? xD (no lo he probado asi que puede que no vaya como debería ir)

PD: podeis compartir esta entrada como http://go.xhiena.net/bLQTMT :P


Comments

  1. Muy interesante la entrada definitivamente lo voy a recomendar, gracias por tan excelente contenido.

  2. Me alegro que te guste :D

  3. El return true de la función checkUrl es lo mejor de todo el post!!!!

    PD: Ná…es solo meterme contigo…yo con las expresiones regulares me pierdo mucho x’D

    PDD: Mola el post nen, cúrrate más de estos que yo de PHP soy azúcar.

    • ejem ejem … xDDD “Por ahora devuelve siempre true a expensas de mejorar la expresión regular para que pille todas las url, ya que las que tienen símbolos raros no pasan este test”

      PD: mamona xD

  4. Oye, pues mola :) Aunque yo con mis conocimientos actuales no pueda aprovecharlo, se entiende xD
    Pero te escribo sobre todo para comentarte que, ya que lo has escrito… ¿no sería lo suyo aprovecharlo?
    Es decir, si le das a compártelo en twitter, por ejemplo, sigues utilizando la url larga Ô_ó
    ¿O no es del todo funcional?

    • Básicamente era una especie de “a ver si lo puedo hacer” es completamente funcional y si vas a http://go.xhiena.net/bLQTMT se dirige a este post.

      Otro tema es integrarlo con el pluggin de wordpress que saca lo de compartir en redes sociales que ya es otro tema digno de otro post xD

  5. Excelente POSTEO te felicito!!!

    Lo que sí al igual que alguien más arriba, me quedó en duda el checkurl ya que yo tampoco tengo soltura con las expresiones regulares, como se podría mejorar para los caracteres extras?

    Por favor una ayuda ya que lo estoy probando pero esto no se como arreglarlo.

    Gracias!!!!!!!!

  6. Esta en chino,porque no entiendo mucho xD.Donde has puesto el archivo de la conexion con la base de datos? eso es lo que no entendi muy bien pero como sea excelente entrada me sirve mucho para mi sitio ya que genera urls mas largas que la muralla china x3.

    Saludos y felicidades por tan buen contenido.

Deja un comentario

Your email address will not be published / Required fields are marked *