API is.gd: Encurtando URLs com o PHP

Atenção! Essa postagem foi escrita há mais de 2 anos. Na informática tudo evolui muito rápido e algumas informações podem estar desatualizadas. Embora o conteúdo possa continuar relevante, lembre-se de levar em conta a data de publicação enquanto estiver lendo. Caso tenha sugestões para atualizá-la, não deixe de comentar!

Sobre o site

O site is.gd é um encurtador de URLs. O serviço básico deles é pegar uma URL grande e transformá-la em pequena.
Decidi começar com esse site porque é a API mais simples que eu encontrei.

Sobre a API

Documentação: http://is.gd/api_info.php
Necessita registro: Não
Limite de uso: Encurtamento de 1000 URLs/dia por IP
Termos de uso: http://is.gd/terms.php

Utilizando a API

O uso do is.gd é muito simples: você envia uma URL e recebe outra. A única limitação é quanto a URLs com mais de 2000 caracteres, o que não deve ser um problema já que é muito raro de se ver isso.

Para a nossa experiência, decidi fazer uma classe para trabalhar com o encurtamento de URLs. Para fins didáticos, não irei trabalhar com métodos e propriedades privados (só um :P) e muito menos com padrões de projeto.

A classe vai funcionar da seguinte maneira: instanciamos o objeto, solicitamos o encurtamento da URL e depois trabalhamos com os dados recebidos.

As propriedades que o nosso objeto deve ter serão as seguintes:
url_original: URL original que foi passada para ser encurtada.
url_curta: URL curta retornada pelo servidor.
erro: true ou false, indicando se houve erro durante a tentativa de encurtar a URL.
erro_msg: no caso de ‘erro’ ser true, aqui fica a mensagem de erro, caso contrário fica como NULL.

E os métodos que utilizaremos:
encurtar: obviamente serve para encurtar a URL. :P
desencurtar: método “brinde” para desencurtar a URL, por que na real a própria API não desencurta as URLs.

Mão na massa

O primeiro passo é montar o corpo da nossa classe. Optei por utilizar um método de encurtar a URL para que o mesmo objeto possa ser utilizado para encurtar várias URLs e também te dá a possibilidade de instanciar o objeto apenas para desencurtar URLs.

Vou dar uma breve explicação do que há no código pois todo ele está comentado. :)

Para fazer o encurtamento precisamos enviar a URL para a API através do método GET.
Por exemplo: http://is.gd/api.php?longurl=phpit.com.br

Desta requisição podem retornar duas coisas: o status 200 (OK) com a URL encurtada ou o status 500 (Internal Server Error) com a mensagem de erro.

O método encurtar preenche as propriedades da classe com os dados pertinentes e retorna true para o caso de ter ocorrido tudo bem e false para o caso de ter dado problema.
Já o método desencurtar apenas retorna a URL desencurtada, sem mexer nas propriedades da classe. Pode também retornar false para o caso de a URL ser inválida.

A seguir você tem a classe na versão comentada e na versão não comentários.

Versão comentada:

<?php
    class isgd {
        
        // Declara as propriedades que serão utilizadas
        public $url_original, $url_curta, $erro, $erro_msg = NULL;
        
        // Este será nosso objeto cURL, o que utilizaremos para acessar a API
        private $curl;
        
        // Nosso método construtor, que será executado quando a classe for instanciada
        public function __construct() {
            // Cria nosso objeto cURL
            $this->curl = curl_init();
            
            // Configura o objeto para retornar os dados ao invés de imprimir na tela
            curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
            /* Configura o objeto para responder a redirecionamentos
               É utilizado no método de desencurtar URLs, pois precisamos seguir até a URL final */
            curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, 1);
        }
        
        // Método para encurtar a URL
        public function encurtar($url) {
            // Utilizamos esta função para codificar os caracteres especiais da URL
            $urlCodificada = rawurlencode($url);
            
            // Esta é a URL que utilizaremos para acessar a API
            $urlApi = 'http://is.gd/api.php?longurl='.$urlCodificada;
            
            // Configuramos a URL no cURL
            curl_setopt($this->curl, CURLOPT_URL, $urlApi);
            
            // Executamos a requisição
            $retorno = curl_exec($this->curl);
            
            // Recebemos os dados da execução
            $dados = curl_getinfo($this->curl);
            
            // O http_code pode ser 200 (OK) e 500 (Internal Server Error)
            /* Junto com a verificação, é bom olhar também se a URL
               possui menos de 20 caracteres, já que o is.gd trabalha
               com no máximo 18. Isto ajuda a evitar error arbitrários. */
            if ($dados['http_code'] == 200 && strlen($retorno) < 20) {
                // Caso tenha ocorrido tudo bem, resetamos estas propriedades
                $this->erro = false;
                $this->erro_msg = NULL;
                $this->url_curta = $retorno;
            } else {
                // Caso tenha dado algum problema, colocamos os dados aqui
                $this->erro = true;
                $this->erro_msg = $retorno;
                $this->url_curta = NULL;
            }
            
            // Colocamos a URL original no seu lugar
            $this->url_original = $url;
            
            /* Por fim, para tornar mais fácil ainda, o retorno da função será
               true ou false dependendo do resultado que obtivemos no processo */
            return $this->erro;
        }
        
        // Método para desencurtar a URL
        public function desencurtar($url) {
            // Primeiro verificamos se a URL é realmente is.gd
            if (substr($url, 0, 13) == 'http://is.gd/' || substr($url, 0, 6) == 'is.gd/') {
                // Configuramos a URL no cURL
                curl_setopt($this->curl, CURLOPT_URL, $url);
                
                // Executamos a requisição
                curl_exec($this->curl);
                
                // Recebemos os dados da execução
                $dados = curl_getinfo($this->curl);
                
                // Testamos se o status é 200 e se a URL retornada é diferente da desencurtada
                if ($dados['http_code'] == 200 && $url != $dados['url']) {
                    // Retornamos a URL desencurtada
                    return $dados['url'];
                }
            }
            // Caso tenha dado algum problema no meio do caminho, retornamos false
            return false;
        }
        
    }
?>

Versão não comentada:

<?php

    class isgd {
        
        public $url_original, $url_curta, $erro, $erro_msg = NULL;
        private $curl;

        public function __construct() {
            $this->curl = curl_init();
            
            curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, 1);
        }

        public function encurtar($url) {
            $urlCodificada = rawurlencode($url);
            $urlApi = 'http://is.gd/api.php?longurl='.$urlCodificada;
            curl_setopt($this->curl, CURLOPT_URL, $urlApi);
            $retorno = curl_exec($this->curl);            
            $dados = curl_getinfo($this->curl);
            
            if ($dados['http_code'] == 200 && strlen($retorno) < 20) {
                $this->erro = false;
                $this->erro_msg = NULL;
                $this->url_curta = $retorno;
            } else {
                $this->erro = true;
                $this->erro_msg = $retorno;
                $this->url_curta = NULL;
            }

            $this->url_original = $url;

            return $this->erro;
        }
        
        public function desencurtar($url) {
            if (substr($url, 0, 13) == 'http://is.gd/' || substr($url, 0, 6) == 'is.gd/') {
                curl_setopt($this->curl, CURLOPT_URL, $url);
                curl_exec($this->curl);
                $dados = curl_getinfo($this->curl);
                if ($dados['http_code'] == 200 && $url != $dados['url']) {
                    return $dados['url'];
                }
            }
            return false;
        }
        
    }

?>

Utilização

Para utilizar a classe é muito simples.

Encurtando uma URL

<?php

    $isgd = new isgd();
    
    if ($isgd->encurtar('http://phpit.com.br')) {
        echo 'URL encurtada: ';
        echo $isgd->url_curta;
    } else {
        echo $isgd->erro_msg;
    }

?>

Vale ressaltar que quando ocorrer tudo certo, teremos o objeto desta forma:

[sourcecode]isgd Object
(
[url_original] => phpit.com.br
[url_curta] => http://is.gd/9Q9kP
[erro] =>
[erro_msg] =>
[curl:private] => Resource id #2
)[/sourcecode]

E quando houver erro teremos algo parecido com isso:

[sourcecode]isgd Object
(
[url_original] => […] uma url muito longa aqui :) […]
[url_curta] =>
[erro] => 1
[erro_msg] => Error: The URL entered was too long.
[curl:private] => Resource id #2
)[/sourcecode]

Desencurtando uma URL

<?php

    $isgd = new isgd();
    
    $url = $isgd->desencurtar('http://is.gd/9Q9kP');
    
    if ($url) {
        echo 'URL encurtada: ';
        echo $url;
    } else {
        echo 'Nao foi possivel desencurtar a URL.';
    }

?>

Conclusão

Bom… Acho que pra primeira API explorada tivemos um trabalho bastante interessante.
Espero que você possa aproveitar (e entender, principalmente) esta classe. Se você fizer melhorias nela, por favor, me mande pois eu gostaria muito de ver!

Aguardo sugestões para as próximas APIs exploradas e quem quiser contribuir com experiências, elas são sempre bem vindas.

Um abraço a todos e fiquem com Deus!