Spanish (Español) translation by Eva Collados Pascual (you can also view the original English article)
OAuth puede ser un concepto complicado a meter en la cabeza al principio, pero con la API de Twitter que requiere ahora su uso, es algo que debes entender antes de crear una aplicación de Twitter. Este tutorial te presentará OAuth y te guiará a través del proceso de creación de una aplicación básica.
Introducción
En este tutorial, vamos a crear una aplicación sencilla que permite a los usuarios aplicar diferentes efectos a su avatar de Twitter. Para trabajar con la API de Twitter, debemos usar OAuth para autorizar a nuestra aplicación a realizar solicitudes en nombre del usuario.
Nuestro flujo de aplicaciones será algo como lo siguiente:
- Se le solicita al usuario que se conecte con Twitter.
- Al usuario se le presenta una lista de avatares de vista previa a partir de la cual hacer una selección.
- Tras la selección, al usuario se le presenta una pantalla de confirmación que muestra el avatar original y el nuevo para que los comparare. También se le ofrece la opción de enviar un tweet.
- Después de que el usuario lo confirme, la aplicación crea y carga el avatar modificado en Twitter y se muestra una página de éxito.
Configuración
Para empezar, debemos configurar nuestro directorio de origen. Necesitamos un directorio lib
para nuestros archivos de biblioteca PHP (clase), un directorio tmp
para mantener archivos temporales (este debe poder ser escrito por el servidor), un directorio css
para nuestra hoja de estilos y un directorio img
para cualquier imagen.
Este es el aspecto que debería tener el árbol de directorios:
- tutorial
- css
- img
- lib
- tmp (grabable)
Registra tu solicitud
Para usar OAuth, necesitarás lo que se denomina clave y secreto de consumidor para identificar tu aplicación. Para obtenerlos, debes registrar una aplicación en Twitter siguiendo estos pasos.
Dirígete a la página de registro, inicia sesión si es necesario. Serás recibido por el formulario que se muestra a continuación:



Rellena el formulario con los detalles correspondientes a tu aplicación. En nuestro caso, el tipo de aplicación es Browser y necesitamos establecer una dirección URL de devolución de llamada predeterminada. Esta URL puede ser cualquier cosa siempre y cuando sea un formato válido. Vamos a reemplazar la devolución de llamada dentro de nuestro código, por lo que no es fundamental que sea una dirección URL real. El tipo de Acceso Predeterminado debe ser Read & Write (Lectura y escritura) para mayor comodidad.
Una vez que te hayas registrado y aceptado los términos, se te presentará información sobre tu nueva solicitud. Los detalles importantes que necesitamos son la Clave del consumidor y el Secreto del consumidor, que deberían tener un aspecto similar al siguiente:



Descarga la Biblioteca tmhOAuth
Vamos a hacer uso de una biblioteca para manejar todos los detalles necesarios para hacer solicitudes OAuth. En este tutorial, usaremos la biblioteca tmhOAuth de @themattharris, que admite la carga de archivos.
- Descarga tmhOAuth desde GitHub
- Extrae tmhOAuth.php en el directorio lib que creamos anteriormente
Autenticación
La autenticación con OAuth es básicamente un proceso de tres pasos. Para obtener una explicación más detallada, consulta esta página sobre autenticación en Twitter, pero aquí tienes un resumen:
- La aplicación obtiene un token de solicitud: el primer paso es que nuestra aplicación se identifique en Twitter (mediante su clave de consumidor) y obtenga un token de solicitud. Tendremos que guardar este token de solicitud para más adelante.
- El usuario autoriza la aplicación en Twitter: El usuario ahora necesita ser enviado a Twitter para conceder a nuestra aplicación acceso a su cuenta. Después de eso, el usuario es redirigido a la dirección URL de devolución de llamada especificada por la aplicación.
- Token de solicitud de intercambios para el token de acceso: ahora que nuestra aplicación ha sido aprobada, puede intercambiar el token de solicitud desde el paso 1 por un token de acceso. Una vez que tengamos el token de acceso, nuestra aplicación es libre de interactuar con la API de Twitter en nombre del usuario.
Así que vamos a empezar con un poco de código. Nos encargaremos de todas las tareas de autenticación en una clase llamada TwitterApp
. Comienza con el siguiente código en un nuevo archivo llamado lib/TwitterApp.php
:
<?php class TwitterApp { /** * This variable holds the tmhOAuth object used throughout the class * * @var tmhOAuth An object of the tmhOAuth class */ public $tmhOAuth; /** * User's Twitter account data * * @var array Information on the current authenticated user */ public $userdata; /** * Authentication state * * Values: * - 0: not authed * - 1: Request token obtained * - 2: Access token obtained (authed) * * @var int The current state of authentication */ protected $state; /** * Initialize a new TwitterApp object * * @param tmhOAuth $tmhOAuth A tmhOAuth object with consumer key and secret */ public function __construct(tmhOAuth $tmhOAuth) { // save the tmhOAuth object $this->tmhOAuth = $tmhOAuth; } }
Aquí hemos creado tres propiedades y un constructor simple. La propiedad $tmhOAuth
será un objeto tmhOAuth, que se usará en toda la clase. La propiedad $userdata
contendrá un objeto que contiene información sobre el usuario, como su nombre de usuario y su estado de Twitter. La propiedad $state
realiza un seguimiento del estado actual de autenticación.
El constructor simplemente acepta un objeto tmhOAuth y lo asigna a la propiedad $tmhOAuth
.
Paso 1: Obtener un token de solicitud
Este es el método para obtener un token de solicitud:
/** * Obtain a request token from Twitter * * @return bool False if request failed */ private function getRequestToken() { // send request for a request token $this->tmhOAuth->request("POST", $this->tmhOAuth->url("oauth/request_token", ""), array( // pass a variable to set the callback 'oauth_callback' => $this->tmhOAuth->php_self() )); if($this->tmhOAuth->response["code"] == 200) { // get and store the request token $response = $this->tmhOAuth->extract_params($this->tmhOAuth->response["response"]); $_SESSION["authtoken"] = $response["oauth_token"]; $_SESSION["authsecret"] = $response["oauth_token_secret"]; // state is now 1 $_SESSION["authstate"] = 1; // redirect the user to Twitter to authorize $url = $this->tmhOAuth->url("oauth/authorize", "") . '?oauth_token=' . $response["oauth_token"]; header("Location: ' . $url); exit; } return false; }
Para entender la primera parte, necesitas conocer el método tmhOAuth::request()
. Este método nos permite realizar una solicitud HTTP habilitada para OAuth y tiene el siguiente uso:
tmhOAuth::request($method, $url[, $params[, $useauth[, $multipart]]])
-
string $method
- El método de solicitud que se va a usar (GET, POST, etc.) -
string $url
- La dirección URL para acceder -
array $params
(opcional) - Matriz asociativa de parámetros a incluir en la solicitud -
bool $useauth
(opcional, predeterminado true) - ¿es necesaria la autenticación? -
bool $multipart
(opcional, predeterminado false) - Se establece en true para las cargas de archivos
Para el parámetro $url
, utilizamos el método tmhOAuth::url()
para crear una URL basada en el método API al que llamamos:
tmhOAuth::url($request[, $format])
-
string $request
- El método api (sin extensión) -
string $format
(opcional, predeterminado ' json") - El formato de respuesta deseado (JSON, XML, etc.)
Ahora que ya estás familiarizado con esos métodos, debemos realizar una solicitud POST al método de API oauth/request_token. Esto devolverá los datos de OAuth en un formato especial, por lo que necesitamos establecer el formato en blanco cuando usemos el método tmhOAuth::url()
. También necesitamos pasar una variable llamada oauth_callback
, que es donde el usuario volverá después de autorizar en Twitter. Usaremos el método tmhOAuth::p hp_self()
para hacer referencia a la página actual. Aquí está ese código otra vez:
// send request for a request token $this->tmhOAuth->request("POST", $this->tmhOAuth->url("oauth/request_token", ""), array( // pass a variable to set the callback 'oauth_callback' => $this->tmhOAuth->php_self() ));
Una vez que realizamos la solicitud, la respuesta se almacena como una matriz en la propiedad tmhOAuth::response
, con los siguientes datos clave:
-
code
- El código de respuesta HTTP -
response
- Los datos reales devueltos -
headers
- Las cabeceras de respuesta
Por lo tanto, la siguiente parte de nuestro código comprueba el código de respuesta (200 significa éxito) y, a continuación, coloca el oauth_token
y oauth_token_secret
que recibimos en variables de sesión, ya que las necesitaremos más adelante. Estos se extraen de los datos de respuesta utilizando el método tmhOAuth::extract_params()
, que devuelve una matriz de datos contenida en la respuesta. También establecemos una variable de sesión authstate
para indicar que estamos en la siguiente etapa de autenticación. Aquí está el código:
if($this->tmhOAuth->response["code"] == 200) { // get and store the request token $response = $this->tmhOAuth->extract_params($this->tmhOAuth->response["response"]); $_SESSION["authtoken"] = $response["oauth_token"]; $_SESSION["authsecret"] = $response["oauth_token_secret"]; // state is now 1 $_SESSION["authstate"] = 1; }
Una vez hecho esto, ahora debemos redirigir al usuario a la URL oauth/authorize, incluyendo el oauth_token
en un parámetro GET. Aquí está ese código otra vez:
// redirect the user to Twitter to authorize $url = $this->tmhOAuth->url("oauth/authorize", "") . '?oauth_token=' . $response["oauth_token"]; header("Location: ' . $url); exit;
Paso 2: Obtener un token de acceso
Este es el método para intercambiar nuestro token de solicitud por un token de acceso:
/** * Obtain an access token from Twitter * * @return bool False if request failed */ private function getAccessToken() { // set the request token and secret we have stored $this->tmhOAuth->config["user_token"] = $_SESSION["authtoken"]; $this->tmhOAuth->config["user_secret"] = $_SESSION["authsecret"]; // send request for an access token $this->tmhOAuth->request("POST", $this->tmhOAuth->url("oauth/access_token", ""), array( // pass the oauth_verifier received from Twitter 'oauth_verifier' => $_GET["oauth_verifier"] )); if($this->tmhOAuth->response["code"] == 200) { // get the access token and store it in a cookie $response = $this->tmhOAuth->extract_params($this->tmhOAuth->response["response"]); setcookie("access_token", $response["oauth_token"], time()+3600*24*30); setcookie("access_token_secret", $response["oauth_token_secret"], time()+3600*24*30); // state is now 2 $_SESSION["authstate"] = 2; // redirect user to clear leftover GET variables header("Location: ' . $this->tmhOAuth->php_self()); exit; } return false; }
Lo primero que hacemos es establecer el user_token
y user_secret
en la matriz tmhOAuth::config
en el token de solicitud que obtuvimos anteriormente.
// set the request token and secret we have stored $this->tmhOAuth->config["user_token"] = $_SESSION["authtoken"]; $this->tmhOAuth->config["user_secret"] = $_SESSION["authsecret"];
La siguiente parte es donde realizamos una solicitud POST a oauth/access_token. Pasamos el oauth_verifier
que recibimos en una variable GET como parámetro en esta solicitud.
// send request for an access token $this->tmhOAuth->request("POST", $this->tmhOAuth->url("oauth/access_token", ""), array( // pass the oauth_verifier received from Twitter 'oauth_verifier' => $_GET["oauth_verifier"] ));
Twitter responderá con un token de acceso y un secreto, que tendremos que guardar para cualquier solicitud futura. Por lo tanto, el siguiente fragmento de código los toma y los guarda cada uno en una cookie y, a continuación, establece el estado en 2.
if($this->tmhOAuth->response["code"] == 200) { // get the access token and store it in a cookie $response = $this->tmhOAuth->extract_params($this->tmhOAuth->response["response"]); setcookie("access_token", $response["oauth_token"], time()+3600*24*30); setcookie("access_token_secret", $response["oauth_token_secret"], time()+3600*24*30); // state is now 2 $_SESSION["authstate"] = 2; // redirect user to clear leftover GET variables header("Location: ' . $this->tmhOAuth->php_self()); exit; }
La redirección al final está ahí para borrar los parámetros de URL dejados por Twitter, y permite que las cookies surtan efecto.
Paso 3: Verificar el token de acceso
Una vez obtenido nuestro token de acceso, debemos comprobarlo para asegurarnos de que es válido. Aquí está el método para hacerlo:
/** * Verify the validity of our access token * * @return bool Access token verified */ private function verifyAccessToken() { $this->tmhOAuth->config["user_token"] = $_COOKIE["access_token"]; $this->tmhOAuth->config["user_secret"] = $_COOKIE["access_token_secret"]; // send verification request to test access key $this->tmhOAuth->request("GET", $this->tmhOAuth->url("1/account/verify_credentials")); // store the user data returned from the API $this->userdata = json_decode($this->tmhOAuth->response["response"]); // HTTP 200 means we were successful return ($this->tmhOAuth->response["code"] == 200); }
Este código ya debería resultarte bastante familiar. Todo lo que hacemos aquí es establecer el user_token
y el user_secret
y hacer una solicitud GET a 1 /account/verify_credentials. Si Twitter responde con un código 200, el token de acceso es válido.
Otro detalle a tener en cuenta es que aquí es donde rellenamos la propiedad $userdata
con los datos devueltos por esta solicitud de Twitter. Los datos están en formato JSON, por lo que usamos json_decode()
para convertirlos en un objeto PHP. Aquí está esa línea otra vez:
// store the user data returned from the API $this->userdata = json_decode($this->tmhOAuth->response["response"]);
Paso 4: Atar todo junto
Con nuestros componentes OAuth en su sitio, es el momento de unirlo todo. Necesitamos un método de orientación pública para permitir que nuestro código de cliente inicie el proceso de autenticación, y aquí está:
/** * Authenticate user with Twitter * * @return bool Authentication successful */ public function auth() { // state 1 requires a GET variable to exist if($this->state == 1 && !isset($_GET["oauth_verifier"])) { $this->state = 0; } // Step 1: Get a request token if($this->state == 0) { return $this->getRequestToken(); } // Step 2: Get an access token elseif($this->state == 1) { return $this->getAccessToken(); } // Step 3: Verify the access token return $this->verifyAccessToken(); }
La mayor parte del método auth()
debería ser autoexplicativo. Según el estado, ejecuta el método adecuado para esa etapa de autenticación. Si el estado es 1, debe existir una variable GET oauth_verifier
, por lo que el método también lo comprueba.
Ahora deberíamos crear un método público para averiguar si estamos autenticados. Este método isAuthed()
devuelve true si el estado es 2:
/** * Check the current state of authentication * * @return bool True if state is 2 (authenticated) */ public function isAuthed() { return $this->state == 2; }
También podemos usar un método para eliminar la autenticación del usuario. Este método endSession()
establece el estado en 0 y elimina las cookies que contienen el token de acceso:
/** * Remove user's access token cookies */ public function endSession() { $this->state = 0; $_SESSION["authstate"] = 0; setcookie("access_token", "", 0); setcookie("access_token_secret", "", 0); }
Inicialización
Ahora necesitamos añadir algunas cosas a nuestro método __construct()
para averiguar en qué estado de autenticación se encuentra la aplicación tras la inicialización. Además, dado que nuestro código utiliza variables de sesión, debemos asegurarnos de que la sesión se inicia con este código:
// start a session if one does not exist if(!session_id()) { session_start(); }
La siguiente parte es donde determinamos el estado. El estado comienza en 0; si hay cookies que contienen un token de acceso, se supone que el estado es 2; en caso contrario, el estado se establece en la variable de sesión authstate
si existe. Aquí está el código:
// determine the authentication status // default to 0 $this->state = 0; // 2 (authenticated) if the cookies are set if(isset($_COOKIE["access_token"], $_COOKIE["access_token_secret"])) { $this->state = 2; } // otherwise use value stored in session elseif(isset($_SESSION["authstate"])) { $this->state = (int)$_SESSION["authstate"]; }
Si el estado es 1, eso significa que estamos en el proceso de autenticación. Así que podemos seguir adelante y continuar el proceso en este punto:
// if we are in the process of authentication we continue if($this->state == 1) { $this->auth(); }
Si el estado es 2, debemos verificar el token de acceso. Si se produce un error en la autenticación, este código borra las cookies y restablece el estado:
// verify authentication, clearing cookies if it fails elseif($this->state == 2 && !$this->auth()) { $this->endSession(); }
Aquí está el nuevo constructor con esos cambios realizados:
/** * Initialize a new TwitterApp object * * @param tmhOAuth $tmhOAuth A tmhOAuth object with consumer key and secret */ public function __construct(tmhOAuth $tmhOAuth) { // save the tmhOAuth object $this->tmhOAuth = $tmhOAuth; // start a session if one does not exist if(!session_id()) { session_start(); } // determine the authentication status // default to 0 $this->state = 0; // 2 (authenticated) if the cookies are set if(isset($_COOKIE["access_token"], $_COOKIE["access_token_secret"])) { $this->state = 2; } // otherwise use value stored in session elseif(isset($_SESSION["authstate"])) { $this->state = (int)$_SESSION["authstate"]; } // if we are in the process of authentication we continue if($this->state == 1) { $this->auth(); } // verify authentication, clearing cookies if it fails elseif($this->state == 2 && !$this->auth()) { $this->endSession(); } }
Envío de un Tweet
Ahora que todo el código de autorización está completo, podemos agregar algunas funciones comunes a nuestra clase. Aquí hay un método para enviar un tweet a través de la API de Twitter:
/** * Send a tweet on the user's behalf * * @param string $text Text to tweet * @return bool Tweet successfully sent */ public function sendTweet($text) { // limit the string to 140 characters $text = substr($text, 0, 140); // POST the text to the statuses/update method $this->tmhOAuth->request("POST", $this->tmhOAuth->url("1/statuses/update"), array( 'status' => $text )); return ($this->tmhOAuth->response["code"] == 200); }
El método sendTweet()
acepta una cadena, la limita a 140 caracteres y, a continuación, la envía en una solicitud POST a 1/statuses/update. Este patrón ya debería ser bastante familiar.
La clase completa de TwitterApp
<?php class TwitterApp { /** * This variable holds the tmhOAuth object used throughout the class * * @var tmhOAuth An object of the tmhOAuth class */ public $tmhOAuth; /** * User's Twitter account data * * @var array Information on the current authenticated user */ public $userdata; /** * Authentication state * * Values: * - 0: not authed * - 1: Request token obtained * - 2: Access token obtained (authed) * * @var int The current state of authentication */ protected $state; /** * Initialize a new TwitterApp object * * @param tmhOAuth $tmhOAuth A tmhOAuth object with consumer key and secret */ public function __construct(tmhOAuth $tmhOAuth) { // save the tmhOAuth object $this->tmhOAuth = $tmhOAuth; // start a session if one does not exist if(!session_id()) { session_start(); } // determine the authentication status // default to 0 $this->state = 0; // 2 (authenticated) if the cookies are set if(isset($_COOKIE["access_token"], $_COOKIE["access_token_secret"])) { $this->state = 2; } // otherwise use value stored in session elseif(isset($_SESSION["authstate"])) { $this->state = (int)$_SESSION["authstate"]; } // if we are in the process of authentication we continue if($this->state == 1) { $this->auth(); } // verify authentication, clearing cookies if it fails elseif($this->state == 2 && !$this->auth()) { $this->endSession(); } } /** * Authenticate user with Twitter * * @return bool Authentication successful */ public function auth() { // state 1 requires a GET variable to exist if($this->state == 1 && !isset($_GET["oauth_verifier"])) { $this->state = 0; } // Step 1: Get a request token if($this->state == 0) { return $this->getRequestToken(); } // Step 2: Get an access token elseif($this->state == 1) { return $this->getAccessToken(); } // Step 3: Verify the access token return $this->verifyAccessToken(); } /** * Obtain a request token from Twitter * * @return bool False if request failed */ private function getRequestToken() { // send request for a request token $this->tmhOAuth->request("POST", $this->tmhOAuth->url("oauth/request_token", ""), array( // pass a variable to set the callback 'oauth_callback' => $this->tmhOAuth->php_self() )); if($this->tmhOAuth->response["code"] == 200) { // get and store the request token $response = $this->tmhOAuth->extract_params($this->tmhOAuth->response["response"]); $_SESSION["authtoken"] = $response["oauth_token"]; $_SESSION["authsecret"] = $response["oauth_token_secret"]; // state is now 1 $_SESSION["authstate"] = 1; // redirect the user to Twitter to authorize $url = $this->tmhOAuth->url("oauth/authorize", "") . '?oauth_token=' . $response["oauth_token"]; header("Location: ' . $url); exit; } return false; } /** * Obtain an access token from Twitter * * @return bool False if request failed */ private function getAccessToken() { // set the request token and secret we have stored $this->tmhOAuth->config["user_token"] = $_SESSION["authtoken"]; $this->tmhOAuth->config["user_secret"] = $_SESSION["authsecret"]; // send request for an access token $this->tmhOAuth->request("POST", $this->tmhOAuth->url("oauth/access_token", ""), array( // pass the oauth_verifier received from Twitter 'oauth_verifier' => $_GET["oauth_verifier"] )); if($this->tmhOAuth->response["code"] == 200) { // get the access token and store it in a cookie $response = $this->tmhOAuth->extract_params($this->tmhOAuth->response["response"]); setcookie("access_token", $response["oauth_token"], time()+3600*24*30); setcookie("access_token_secret", $response["oauth_token_secret"], time()+3600*24*30); // state is now 2 $_SESSION["authstate"] = 2; // redirect user to clear leftover GET variables header("Location: ' . $this->tmhOAuth->php_self()); exit; } return false; } /** * Verify the validity of our access token * * @return bool Access token verified */ private function verifyAccessToken() { $this->tmhOAuth->config["user_token"] = $_COOKIE["access_token"]; $this->tmhOAuth->config["user_secret"] = $_COOKIE["access_token_secret"]; // send verification request to test access key $this->tmhOAuth->request("GET", $this->tmhOAuth->url("1/account/verify_credentials")); // store the user data returned from the API $this->userdata = json_decode($this->tmhOAuth->response["response"]); // HTTP 200 means we were successful return ($this->tmhOAuth->response["code"] == 200); } /** * Check the current state of authentication * * @return bool True if state is 2 (authenticated) */ public function isAuthed() { return $this->state == 2; } /** * Remove user's access token cookies */ public function endSession() { $this->state = 0; $_SESSION["authstate"] = 0; setcookie("access_token", "", 0); setcookie("access_token_secret", "", 0); } /** * Send a tweet on the user's behalf * * @param string $text Text to tweet * @return bool Tweet successfully sent */ public function sendTweet($text) { // limit the string to 140 characters $text = substr($text, 0, 140); // POST the text to the statuses/update method $this->tmhOAuth->request("POST", $this->tmhOAuth->url("1/statuses/update"), array( 'status' => $text )); return ($this->tmhOAuth->response["code"] == 200); } }
Nuestra aplicación
Ahora que tenemos una clase que controla todas las tareas de OAuth, ahora podemos ampliarla con funcionalidad específica para nuestra aplicación. Esto incluye la capacidad de obtener, alterar y establecer el avatar del usuario.
Vamos a extender la clase TwitterApp con una clase TwitterAvatars. Comienza con el siguiente código en un nuevo archivo llamado lib/TwitterAvatars.php
:
<?php class TwitterAvatars extends TwitterApp { /** * The path to our temporary files directory * * @var string Path to store image files */ public $path; /** * These are all the GD image filters available in this class * * @var array Associative array of image filters */ protected $filters = array( 'grayscale' => IMG_FILTER_GRAYSCALE, 'negative' => IMG_FILTER_NEGATE, 'edgedetect' => IMG_FILTER_EDGEDETECT, 'embossed' => IMG_FILTER_EMBOSS, 'blurry' => IMG_FILTER_GAUSSIAN_BLUR, 'sketchy' => IMG_FILTER_MEAN_REMOVAL ); /** * Initialize a new TwitterAvatars object * * @param tmhOAuth $tmhOAuth A tmhOAuth object with consumer key and secret * @param string $path Path to store image files (default 'tmp") */ public function __construct(tmhOAuth $tmhOAuth, $path = 'tmp") { // call the parent class' constructor parent::__construct($tmhOAuth); // save the path variable $this->path = $path; } }
Como puedes ver, la clase extendida incluye una propiedad $path
para apuntar a donde irán los archivos de imagen temporales, una propiedad $filters
que contiene una matriz de filtros de imagen y un constructor extendido con un parámetro para establecer la ruta de acceso. Como estamos reemplazando el constructor original, tenemos que llamar explícitamente al constructor del elemento primario con parent::__construct()
.
Ahora podemos empezar a añadir nuestros métodos.
Descargar
Obviamente, necesitaremos la capacidad de descargar imágenes para manipularlas. Aquí hay un método genérico download()
que acepta una URL y devuelve los datos en esa ubicación. El método realiza una solicitud cURL básica.
/** * Download data from specified URL * * @param string $url URL to download * @return string Downloaded data */ protected function download($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $ret = curl_exec($ch); curl_close($ch); return $ret; }
Búsqueda de URLs
Ahora que podemos descargar archivos, necesitamos encontrar la ubicación de los archivos que necesitamos. Hay dos imágenes diferentes que nos interesan, la miniatura de tamaño estándar y la imagen original de tamaño completo. Por lo tanto, crearemos un método para obtener cada una de las URL.
Para obtener la miniatura de tamaño estándar, llamaremos al método de API users/profile_image/:screen_name que responde con una redirección 302 a la imagen de avatar del usuario especificado. Esto significa que la dirección URL se encuentra en la cabecera Location. Aquí está ese método:
/** * Get the URL to the standard sized avatar * * @return string The URL to the image file */ protected function getImageURL() { // request user's 'bigger' profile image $this->tmhOAuth->request("GET", $this->tmhOAuth->url("1/users/profile_image/" . $this->userdata->screen_name), array( 'screen_name' => $this->userdata->screen_name, 'size' => 'bigger' )); if($this->tmhOAuth->response["code"] == 302) { // the direct URL is in the Location header return $this->tmhOAuth->response["headers"]["location"]; } throw new Exception("Error locating image"); }
Ten en cuenta que estamos realizando una solicitud GET con tmhOAuth, pasando los parámetros screen_name
y size
, a continuación, devolviendo el contenido de la cabecera Location.
No hay ningún método de API para obtener la imagen de tamaño completo, por lo que para nuestro siguiente método vamos a hacer un poco de trampa y editaremos la URL. Los datos de usuario contienen un campo profile_image_url
que apunta a algo como avatar_normal.jpg, y la imagen original se puede encontrar en avatar.jpg sin el sufijo. Por lo tanto, este método obtiene la dirección URL, quita el sufijo de tamaño y devuelve la dirección URL modificada:
/** * Get the URL to the full sized avatar * * @return string The URL to the image file */ protected function getOriginalImageURL() { // get the regular sized avatar $url = $this->userdata->profile_image_url; // save the extension for later $ext = strrchr($url, '."); // strip the "_normal' suffix and add back the extension return substr($url, 0, strrpos($url, "_")) . $ext; }
Lectura de imágenes
Ahora que podemos localizar y descargar imágenes, necesitamos una forma de leerlas. Usaremos la biblioteca GD para manipularlas, por lo que este método convertirá los datos de imagen sin procesar en un recurso de imagen GD.
/** * Convert raw image data to a GD resource * * @param string $data Binary image data to parse * @return resource A GD image resource identifier */ protected function readImage($data) { // read in the original image $src = imagecreatefromstring($data); if(!$src) { throw new Exception("Error reading image"); } // get the dimensions $width = imagesx($src); $height = imagesy($src); // create a blank true color image of the same size $img = imagecreatetruecolor($width, $height); // copy the original image to this new canvas imagecopy($img, $src, 0, 0, 0, 0, $width, $height); // discard the source image imagedestroy($src); return $img; }
Para describir lo que está sucediendo arriba:
- Los datos de imagen se convierten en un recurso GD mediante la función
imagecreatefromstring()
. - Las dimensiones de la imagen se graban utilizando
imagesx()
eimagesy()
. - Se crea una nueva imagen de color verdadero en blanco con las mismas dimensiones utilizando
imagecreatetruecolor()
. - La imagen original se copia en la nueva imagen utilizando la función
imagecopy()
. Esto da como resultado una versión en color real de la imagen original independientemente del modo de color original. - El recurso de imagen original se destruye mediante
imagedestroy()
y se devuelve el identificador de la nueva imagen.
Guardar imágenes
Ahora que podemos descargar imágenes y crear un recurso GD, necesitamos un método para guardarlas en el sistema de archivos. Este es el método que guarda la imagen proporcionada como un archivo PNG con el nombre especificado utilizando imagepng()
:
/** * Save a GD image resource to a PNG file * * @param resource $img GD image resource identifier * @param string $name Name of the image * @return string Path to the saved image */ protected function saveImage($img, $name) { $path = $this->path . "/' . $name . '.png'; imagepng($img, $path); imagedestroy($img); return $path; }
Generar las vistas previas
Ahora que tenemos todas las piezas que alimentan nuestra aplicación, podemos empezar a juntarlas. En nuestro flujo de aplicaciones, le daremos al usuario una selección de vistas previas entre las que elegir. Aquí está el método para generar estas vistas previas:
/** * Generate previews for each image filter * * @return array Associative array of image previews */ public function generatePreviews() { // we need valid user info to know whose avatar to handle if(!$this->isAuthed()) { throw new Exception("Requires oauth authorization"); } $username = $this->userdata->screen_name; // cache the raw data to use $data = $this->download($this->getImageURL()); // copy the original image $img = $this->readImage($data); $this->saveImage($img, $username . "_orig"); // array to hold the list of previews $images = array(); // loop through each filter to generate previews foreach($this->filters as $filter_name => $filter) { $img = $this->readImage($data); imagefilter($img, $filter); $images[$filter_name] = $this->saveImage($img, $username . "_' . $filter_name); } return $images; }
Lo primero que hacemos es comprobar que el usuario está autenticado y, a continuación, agarrar el nombre de usuario para usarlo más adelante en los nombres de archivo.
// we need valid user info to know whose avatar to handle if(!$this->isAuthed()) { throw new Exception("Requires oauth authorization"); } $username = $this->userdata->screen_name;
Luego descargamos la imagen del usuario usando los métodos getImageURL()
y download()
que hemos creado. Estos datos se utilizarán repetidamente para cada vista previa, por lo que los guardamos en la variable $data
.
// cache the raw data to use $data = $this->download($this->getImageURL());
A continuación, guardamos una copia sin modificar con el sufijo _orig. Esto lo usaremos más adelante para la comparación visual.
// copy the original image $img = $this->readImage($data); $this->saveImage($img, $username . "_orig");
La última parte del método es donde recorremos los filtros de imagen enumerados en la propiedad $filters
, generando una imagen para cada filtro. En cada iteración, estamos creando una imagen y aplicando la función imagefilter()
, que acepta una de las constantes que hemos enumerado en la matriz $filters
. Luego, para cada imagen que guardamos, añadimos su ruta de acceso a una matriz asociativa (usando el nombre del filtro como la clave) que este método devuelve al final.
// array to hold the list of previews $images = array(); // loop through each filter to generate previews foreach($this->filters as $filter_name => $filter) { $img = $this->readImage($data); imagefilter($img, $filter); $images[$filter_name] = $this->saveImage($img, $username . "_' . $filter_name); } return $images;
La siguiente parte de nuestro flujo de aplicaciones pide al usuario que confirme su elección, por lo que necesitamos una manera de encontrar una vista previa específica. Aquí está el método simple para obtener la ruta a una imagen basada en la opción pasada como parámetro, por defecto a la imagen original:
/** * Get the path to a previously generated preview * * @param string $filter The image filter to get the preview for * @return string The path to the preview file or null if not found */ public function getPreview($filter = 'orig") { if(!$this->isAuthed()) { throw new Exception("Requires oauth authorization"); } $path = $this->path . "/' . $this->userdata->screen_name . "_' . $filter . '.png'; if(file_exists($path)) { return $path; } return null; }
Cambiar el avatar
La etapa final de nuestro flujo de aplicaciones es realmente cambiar el avatar del usuario. Primero necesitamos un método para obtener la imagen de tamaño completo y aplicar un filtro específico a ella. Aquí está:
/** * Process the user's full avatar using one of the filters * * @param string $filter The filter to apply to the image * @return string Path to the output file */ protected function processImage($filter = "grayscale") { // make sure the filter exists $filter = strtolower($filter); if(!array_key_exists($filter, $this->filters)) { throw new Exception("Unsupported image filter"); } $username = $this->userdata->screen_name; // get the full sized avatar $data = $this->download($this->getOriginalImageURL()); $img = $this->readImage($data); // apply the filter to the image imagefilter($img, $this->filters[$filter]); // save the image and return the path return $this->saveImage($img, $username . "_' . $filter . "_full"); }
Eso debería ser fácil de seguir ya que es muy similar al método generatePreviews()
. Acepta un parámetro para especificar un filtro de imagen y comprueba que existe. A continuación, descarga la imagen original y le aplica el filtro, pasando de nuevo la ruta de acceso a la imagen generada como valor devuelto.
Ahora necesitamos el método que realmente envía la imagen generada a Twitter, actualizando el avatar del usuario. Este método llama al método processImage()
para crear la imagen y la carga en Twitter a través del método API 1/account/update_profile_image:
/** * Update user's avatar with a filtered version * * @param string $filter The filter to use * @return bool Operation successful */ public function commitAvatar($filter) { if(!$this->isAuthed()) { throw new Exception("Requires oauth authorization"); } // generate the image and get the path $path = $this->processImage($filter); if(file_exists($path)) { // send a multipart POST request with the image file data $this->tmhOAuth->request("POST", $this->tmhOAuth->url("1/account/update_profile_image"), array( // format: @local/path.png;type=mime/type;filename=file_name.png 'image' => '@' . $path . ';type=image/png;filename=' . basename($path) ), true, true); return ($this->tmhOAuth->response["code"] == 200); } return false; }
La parte complicada aquí es la solicitud POST tmhOAuth real, que es una solicitud multiparte que contiene los datos de imagen sin procesar. Para ello, debemos establecer el último parámetro del método tmhOAuth::request()
en true
, y pasar la variable de image
en un formato especial:
@[path_to_image];type=[mime_type];filename=[file_name]
Por ejemplo, si queremos cargar tmp/username_grayscale_full.png, el valor sería @tmp/username_grayscale_full.png;type-image/png;filename-username_grayscale_full.png
.
Aquí está esa parte del código de nuevo:
// send a multipart POST request with the image file data $this->tmhOAuth->request("POST", $this->tmhOAuth->url("1/account/update_profile_image"), array( // format: @local/path.png;type=mime/type;filename=file_name.png 'image' => '@' . $path . ';type=image/png;filename=' . basename($path) ), true, true);
Hacer limpieza
Un efecto secundario de toda esta manipulación de archivos es una gran cantidad de archivos temporales que se quedan atrás. Aquí tienes un método para limpiar el directorio temporal:
/** * Delete leftover image files */ public function cleanupFiles() { // file to track when we last checked $flag = $this->path . "/.last_check'; $time = time(); // have we checked within the last hour? if(!file_exists($flag) || $time - filemtime($flag) > 3600) { // get an array of PNG files in the directory $files = glob($this->path . "/*.png"); // loop through files, deleting old files (12+ hours) foreach($files as $file) { if($time - filemtime($file) > 60*60*12) { unlink($file); } } // update the timestamp of our flag file touch($flag); } }
Esto simplemente recorre los archivos PNG, eliminando los que tengan una antiguedad mayor de 12 horas. También comprueba cuánto tiempo ha pasado desde que lo comprobamos usando la marca de tiempo en un archivo .last_check, lo que nos permite limitar la comprobación a una por hora. De esta manera podemos llamar a este método en cada solicitud sin desperdiciar recursos.
Nota: Estamos haciendo uso de la función glob()
en PHP, que es una manera fácil de obtener una matriz de archivos que coincidan con un patrón.
La clase completa de TwitterAvatars
&?php class TwitterAvatars extends TwitterApp { /** * The path to our temporary files directory * * @var string Path to store image files */ public $path; /** * These are all the GD image filters available in this class * * @var array Associative array of image filters */ protected $filters = array( 'grayscale' => IMG_FILTER_GRAYSCALE, 'negative' => IMG_FILTER_NEGATE, 'edgedetect' => IMG_FILTER_EDGEDETECT, 'embossed' => IMG_FILTER_EMBOSS, 'blurry' => IMG_FILTER_GAUSSIAN_BLUR, 'sketchy' => IMG_FILTER_MEAN_REMOVAL ); /** * Initialize a new TwitterAvatars object * * @param tmhOAuth $tmhOAuth A tmhOAuth object with consumer key and secret * @param string $path Path to store image files (default 'tmp") */ public function __construct(tmhOAuth $tmhOAuth, $path = 'tmp") { // call the parent class' constructor parent::__construct($tmhOAuth); // save the path variable $this->path = $path; } /** * Download data from specified URL * * @param string $url URL to download * @return string Downloaded data */ protected function download($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $ret = curl_exec($ch); curl_close($ch); return $ret; } /** * Get the URL to the standard sized avatar * * @return string The URL to the image file */ protected function getImageURL() { // request user's 'bigger' profile image $this->tmhOAuth->request("GET", $this->tmhOAuth->url("1/users/profile_image/' . $this->userdata->screen_name), array( 'screen_name' => $this->userdata->screen_name, 'size' => 'bigger' )); if($this->tmhOAuth->response["code"] == 302) { // the direct URL is in the Location header return $this->tmhOAuth->response["headers"]["location"]; } throw new Exception("Error locating image"); } /** * Get the URL to the full sized avatar * * @return string The URL to the image file */ protected function getOriginalImageURL() { // get the regular sized avatar $url = $this->userdata->profile_image_url; // save the extension for later $ext = strrchr($url, '."); // strip the "_normal' suffix and add back the extension return substr($url, 0, strrpos($url, "_")) . $ext; } /** * Convert raw image data to a GD resource * * @param string $data Binary image data to parse * @return resource A GD image resource identifier */ protected function readImage($data) { // read in the original image $src = imagecreatefromstring($data); if(!$src) { throw new Exception("Error reading image"); } // get the dimensions $width = imagesx($src); $height = imagesy($src); // create a blank true color image of the same size $img = imagecreatetruecolor($width, $height); // copy the original image to this new canvas imagecopy($img, $src, 0, 0, 0, 0, $width, $height); // discard the source image imagedestroy($src); return $img; } /** * Save a GD image resource to a PNG file * * @param resource $img GD image resource identifier * @param string $name Name of the image * @return string Path to the saved image */ protected function saveImage($img, $name) { $path = $this->path . "/' . $name . '.png'; imagepng($img, $path); imagedestroy($img); return $path; } /** * Generate previews for each image filter * * @return array Associative array of image previews */ public function generatePreviews() { // we need valid user info to know whose avatar to handle if(!$this->isAuthed()) { throw new Exception("Requires oauth authorization"); } $username = $this->userdata->screen_name; // cache the raw data to use $data = $this->download($this->getImageURL()); // copy the original image $img = $this->readImage($data); $this->saveImage($img, $username . "_orig"); // array to hold the list of previews $images = array(); // loop through each filter to generate previews foreach($this->filters as $filter_name => $filter) { $img = $this->readImage($data); imagefilter($img, $filter); $images[$filter_name] = $this->saveImage($img, $username . "_' . $filter_name); } return $images; } /** * Get the path to a previously generated preview * * @param string $filter The image filter to get the preview for * @return string The path to the preview file or null if not found */ public function getPreview($filter = 'orig") { if(!$this->isAuthed()) { throw new Exception("Requires oauth authorization"); } $path = $this->path . "/' . $this->userdata->screen_name . "_' . $filter . '.png'; if(file_exists($path)) { return $path; } return null; } /** * Process the user's full avatar using one of the filters * * @param string $filter The filter to apply to the image * @return string Path to the output file */ protected function processImage($filter = 'grayscale") { // make sure the filter exists $filter = strtolower($filter); if(!array_key_exists($filter, $this->filters)) { throw new Exception("Unsupported image filter"); } $username = $this->userdata->screen_name; // get the full sized avatar $data = $this->download($this->getOriginalImageURL()); $img = $this->readImage($data); // apply the filter to the image imagefilter($img, $this->filters[$filter]); // save the image and return the path return $this->saveImage($img, $username . "_' . $filter . "_full"); } /** * Update user's avatar with a filtered version * * @param string $filter The filter to use * @return bool Operation successful */ public function commitAvatar($filter) { if(!$this->isAuthed()) { throw new Exception("Requires oauth authorization"); } // generate the image and get the path $path = $this->processImage($filter); if(file_exists($path)) { // send a multipart POST request with the image file data $this->tmhOAuth->request("POST", $this->tmhOAuth->url("1/account/update_profile_image"), array( // format: @local/path.png;type=mime/type;filename=file_name.png 'image' => '@' . $path . ';type=image/png;filename=' . basename($path) ), true, true); return ($this->tmhOAuth->response["code"] == 200); } return false; } /** * Delete leftover image files */ public function cleanupFiles() { // file to track when we last checked $flag = $this->path . "/.last_check'; $time = time(); // have we checked within the last hour? if(!file_exists($flag) || $time - filemtime($flag) > 3600) { // get an array of PNG files in the directory $files = glob($this->path . "/*.png"); // loop through files, deleting old files (12+ hours) foreach($files as $file) { if($time - filemtime($file) > 60*60*12) { unlink($file); } } // update the timestamp of our flag file touch($flag); } } }
El front end
Tenemos todos los componentes de la aplicación juntos, así que ahora todo lo que necesitamos es la interfaz de usuario. Todo el código aquí irá al archivo index.php en el directorio raíz. Comenzaremos incluyendo las bibliotecas y estableciendo la configuración:
<?php // include our libraries include 'lib/tmhOAuth.php'; include 'lib/TwitterApp.php'; include 'lib/TwitterAvatars.php'; // set the consumer key and secret define("CONSUMER_KEY", 'qSkJum23MqlG6greF8Z76A"); define("CONSUMER_SECRET", 'Bs738r5UY2R7e5mwp1ilU0voe8OtXAtifgtZe9EhXw"); ?>
Nota: Asegúrate de reemplazar el CONSUMER_KEY
y CONSUMER_SECRET
por el tuyo propio.
Vamos a colocar nuestro código en un bloque try-catch para que podamos manejar correctamente cualquier error, asignando su mensaje a una variable $error
.
try { } catch(Exception $e) { // catch any errors that may occur $error = $e; }
Dentro del bloque try podemos comenzar a escribir nuestro código, comenzando inicializando un objeto TwitterAvatars llamado $ta
con un objeto tmhOAuth configurado:
// our tmhOAuth settings $config = array( 'consumer_key' => CONSUMER_KEY, 'consumer_secret' => CONSUMER_SECRET ); // create a new TwitterAvatars object $ta = new TwitterAvatars(new tmhOAuth($config));
En este momento podemos borrar cualquier archivo temporal antiguo:
// check for stale files $ta->cleanupFiles();
A continuación comprobamos si el usuario está autenticado o, en su defecto, si el usuario ha solicitado la autenticación, en cuyo caso iniciamos el proceso llamando al método auth()
:
// check our authentication status if($ta->isAuthed()) { } // did the user request authorization? elseif(isset($_POST["auth"])) { // start authentication process $ta->auth(); }
Si el usuario está autenticado, necesitamos comprobar si ha seleccionado una opción, de lo contrario generaremos vistas previas:
// check our authentication status if($ta->isAuthed()) { // has the user selected an option? if(isset($_POST["filter"])) { } // generate previews if the user has not chosen else { // $previews will be a list of images $previews = $ta->generatePreviews(); } }
Si se ha seleccionado una opción, necesitamos obtener las rutas a las imágenes antiguas y nuevas para su visualización:
// has the user selected an option? if(isset($_POST["filter"])) { // get the image paths for display $original = $ta->getPreview(); $newimage = $ta->getPreview($_POST["filter"]); }
Por último, comprobamos si el usuario ha confirmado su elección y aplicamos el cambio. También enviamos un tweet si se solicita y establecemos una variable $success
en true
:
// has the user selected an option? if(isset($_POST["filter"])) { // is the user sure? if(isset($_POST["confirm"])) { // change the user's avatar $ta->commitAvatar($_POST["filter"]); // tweet if the user chose to if(isset($_POST["tweet"])) { $ta->sendTweet("I just updated my avatar using Avatar Effects..."); } $success = true; } // get the image paths for display $original = $ta->getPreview(); $newimage = $ta->getPreview($_POST["filter"]); }
Esto es lo que tenemos hasta ahora:
<?php // include our libraries include 'lib/tmhOAuth.php'; include 'lib/TwitterApp.php'; include 'lib/TwitterAvatars.php'; // set the consumer key and secret define("CONSUMER_KEY", 'qSkJum23MqlG6greF8Z76A"); define("CONSUMER_SECRET", 'Bs738r5UY2R7e5mwp1ilU0voe8OtXAtifgtZe9EhXw"); try { // our tmhOAuth settings $config = array( 'consumer_key' => CONSUMER_KEY, 'consumer_secret' => CONSUMER_SECRET ); // create a new TwitterAvatars object $ta = new TwitterAvatars(new tmhOAuth($config)); // check for stale files $ta->cleanupFiles(); // check our authentication status if($ta->isAuthed()) { // has the user selected an option? if(isset($_POST["filter"])) { // is the user sure? if(isset($_POST["confirm"])) { // change the user's avatar $ta->commitAvatar($_POST["filter"]); // tweet if the user chose to if(isset($_POST["tweet"])) { $ta->sendTweet("I just updated my avatar using Avatar Effects..."); } $success = true; } // get the image paths for display $original = $ta->getPreview(); $newimage = $ta->getPreview($_POST["filter"]); } // generate previews if the user has not chosen else { // $previews will be a list of images $previews = $ta->generatePreviews(); } } // did the user request authorization? elseif(isset($_POST["auth"])) { // start authentication process $ta->auth(); } } catch(Exception $e) { // catch any errors that may occur $error = $e; } ?>
El HTML
Después del código PHP vamos a generar el HTML apropiado, comenzando con esta plantilla, que establece el título y el encabezado principal:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Twitter Avatar Effects</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <h1>Twitter Avatar Effects</h1> </body> </html>
Aquí es donde mostramos un formulario con entradas de imagen para cada vista previa:
<?php if(isset($previews)): ?> <h2>Choose your weapon...</h2> <form action="index.php" method="post"> <?php foreach($previews as $filter => $path): ?> <input type="image" src="<?php echo $path; ?>" alt="<?php echo ucfirst($filter); ?>" width="73" height="73" name="filter" value="<?php echo $filter; ?>"> <?php endforeach; ?> </form> <p>Select one of the images above to change your Twitter avatar.</p>
Aquí está la página de éxito:
<?php elseif(isset($success)): ?> <h2>Success! Your Twitter avatar is now:</h2> <img src="<?php echo $newimage; ?>" alt="Your Avatar" width="73" height="73"> <p><a href="http://twitter.com/<?php echo $ta->userdata->screen_name; ?>">Go see it</a></p>
Aquí está la página de confirmación, donde mostramos la comparación y ofrecemos la oportunidad de cancelar:
<?php elseif(isset($newimage)): ?> <h2>Are you sure?</h2> <img src="<?php echo $original; ?>" alt="Original" width="73" height="73"> <span class="arrow">⇒</span> <img src="<?php echo $newimage; ?>" alt="<?php echo ucfirst($_POST["filter"]); ?>"> <form action="index.php" method="post"> <input type="hidden" name="filter" value="<?php echo $_POST["filter"]; ?>"> <input type="submit" name="confirm" value="Confirm"> <a href="index.php">Cancel</a> <p><label>Tweet about your new avatar? <input type="checkbox" name="tweet" value="true"></label></p> </form>
Ten en cuenta que el formulario de confirmación incluye el filtro seleccionado en un campo oculto.
Si tiene lugar un error, mostramos esto:
<?php elseif(isset($error)): ?> <p>Error. <a href="index.php">Try again?</a></p>
La pantalla predeterminada es el botón "Conectarse a Twitter" como entrada de imagen (descargar una de las imágenes desde la parte inferior de esta página al directorio img):
<?php else: ?> <form action="index.php" method="post"> <input type="image" src="img/sign-in-with-twitter-l.png" alt="Connect to Twitter" name="auth" value="1"> </form> <p>Connect to Twitter to use this app.</p> <?php endif; ?>
Aquí está la sección HTML completa:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Twitter Avatar Effects</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <h1>Twitter Avatar Effects</h1> <?php if(isset($previews)): ?> <h2>Choose your weapon...</h2> <form action="index.php" method="post"> <?php foreach($previews as $filter => $path): ?> <input type="image" src="<?php echo $path; ?>" alt="<?php echo ucfirst($filter); ?>" width="73" height="73" name="filter" value="<?php echo $filter; ?>"> <?php endforeach; ?> </form> <p>Select one of the images above to change your Twitter avatar.</p> <?php elseif(isset($success)): ?> <h2>Success! Your Twitter avatar is now:</h2> <img src="<?php echo $newimage; ?>" alt="Your Avatar" width="73" height="73"> <p><a href="http://twitter.com/<?php echo $ta->userdata->screen_name; ?>">Go see it</a></p> <?php elseif(isset($newimage)): ?> <h2>Are you sure?</h2> <img src="<?php echo $original; ?>" alt="Original" width="73" height="73"> <span class="arrow">⇒</span> <img src="<?php echo $newimage; ?>" alt="<?php echo ucfirst($_POST["filter"]); ?>"> <form action="index.php" method="post"> <input type="hidden" name="filter" value="<?php echo $_POST["filter"]; ?>"> <input type="submit" name="confirm" value="Confirm"> <a href="index.php">Cancel</a> <p><label>Tweet about your new avatar? <input type="checkbox" name="tweet" value="true"></label></p> </form> <?php elseif(isset($error)): ?> <p>Error. <a href="index.php">Try again?</a></p> <?php else: ?> <form action="index.php" method="post"> <input type="image" src="img/sign-in-with-twitter-l.png" alt="Connect to Twitter" name="auth" value="1"> </form> <p>Connect to Twitter to use this app.</p> <?php endif; ?> </body> </html>
El CSS
Aquí tenemos un CSS básico para hacer que la interfaz se vea agradable, guardado en css/style.css:
html { background-color: #eee; text-align: center; font-family: "Lucida Grande",Verdana, sans-serif; font-size: 16px; color: #224; } body { width: 700px; margin: 30px auto; background-color: #acf; padding: 10px; border-radius: 10px; -moz-border-radius: 10px; -webkit-border-radius: 10px; } p { font-size: 1em; } h1 { font-size: 2em; } h2 { font-size: 1.6em; } .arrow { font-size: 4em; font-weight: bold; }
Resultados
Aquí hay un video que detalla cómo debería verse nuestra aplicación completa:
Conclusión
Si has seguido este tutorial hasta el final, deberías tener una muy buena comprensión de OAuth y lo que se necesita para crear una sencilla aplicación web de Twitter. Usar la API de Twitter es fácil una vez que entiendes los conceptos básicos, especialmente si usas una biblioteca como tmhOAuth para manejar los detalles menores.
El ejemplo simple que creamos en este tutorial se puede modificar o ampliar fácilmente para hacer cualquier cosa. Así que si tienes una gran idea para una nueva y refrescante aplicación de Twitter, no dudes en utilizar esto como base.
Gracias por leer. Si tienes alguna pregunta o comentario sobre este tutorial, ¡por favor publícalo!