rss
twitter
  •  

CodeIgniter – URL amigable con guión

| Posted in General |

0

Codeigniter, así como muchos otros frameworks están basados en MVC, y los controladores al ser clases de POO, sus nombres y métodos no pueden llevar guión “-”

Así pues una URL típica del método MVC sería:
dominio.com/controlador/método/dato1/dato2

Pero qué sucede si quiero URLs más amigables para los motores de búsqueda, para el dichoso SEO ;-) algo como:
dominio.com/controlador-principal/

Pues no podría de buenas a primeras jugando con el nombre del controlador, es por ello que recurrimos a la manipulación del enrutado (routing) el cual encontramos en el archivo routes.php


$route['(.+)-(.+)-(.+)-(.+)-(.+)'] = “$1_$2_$3_$4_$5″;
$route['(.+)-(.+)-(.+)-(.+)'] = “$1_$2_$3_$4″;
$route['(.+)-(.+)-(.+)'] = “$1_$2_$3″;
$route['(.+)-(.+)'] = “$1_$2″;

Así soporta URLs con guiones de hasta 5 segmentos, por ejemplo, si tenemos nuestra dirección “dominio.com/analisis-precio-unitario”, estas líneas reescribirán y llamará a la clase “dominio.com/analisis_precio_unitario”.

Si necesitas más segmentos, solamente ve añadiendo más líneas siguiendo el mismo patrón.

Gracias a http://www.wakamolee.com/ por el dato !

Sesiones tradicionales en Codeigniter

| Posted in General |

4

Como muchos ya saben, el tradicional superglobal $_SESSION no está disponible en CodeIgniter y peor aun, las sesiones ni siquiera se almacenan del lado del servidor… son sólo vulgares cookies ! (lo que pone en riesgo la sensibilidad de los datos e incompatibilidad con ciertos navegadores).

Es tan tiránica esta filosofía que cuando mucho se te permite almacenarlas en una base de datos (algo absurdo para un proyecto pequeño).

En supuesto favor a la seguridad, resultó convertirse en su talón de Aquiles (son cientos de programadores como yo que han mostrado su disgusto por esta absurda forma de manejar los datos). Lo que justificó el nacimiento de Kohana.

En fin… como la comunidad es abierta y siempre hay gente inteligente en todos lados, no tardó alguien en crear una librería que remplaza al 100% la librería estándar Session.php que maneja por defecto las sesiones en CodeIgniter permitiéndonos usar los mismos métodos descritos en el manual oficial … pero comportándose como se supone debería comportarse.

Sólo necesitamos cargar la librería como acostumbramos hacer:

$this->load->library('session');

Y colocar nuestro archivo Session.php en nuestro application/libraries/


<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
* Session class using native PHP session features and hardened against session fixation.
*
* @package     CodeIgniter
* @subpackage  Libraries
* @category    Sessions
* @author      Dariusz Debowczyk
* @link        http://www.codeigniter.com/user_guide/libraries/sessions.html
*/
class CI_Session {

	var $flash_key = 'flash'; // prefix for "flash" variables (eg. flash:new:message)

	function CI_Session()
	{
		$this->object =& get_instance();
		log_message('debug', "Native_session Class Initialized");
		$this->_sess_run();
	}

	/**
    * Regenerates session id
    */
	function regenerate_id()
	{
		// copy old session data, including its id
		$old_session_id = session_id();
		$old_session_data = $_SESSION;

		// regenerate session id and store it
		session_regenerate_id();
		$new_session_id = session_id();

		// switch to the old session and destroy its storage
		session_id($old_session_id);
		session_destroy();

		// switch back to the new session id and send the cookie
		session_id($new_session_id);
		session_start();

		// restore the old session data into the new session
		$_SESSION = $old_session_data;

		// update the session creation time
		$_SESSION['regenerated'] = time();

		// session_write_close() patch based on this thread
		// http://www.codeigniter.com/forums/viewthread/1624/
		// there is a question mark ?? as to side affects

		// end the current session and store session data.
		session_write_close();
	}

	/**
    * Destroys the session and erases session storage
    */
	function destroy()
	{
		unset($_SESSION);
		if ( isset( $_COOKIE[session_name()] ) )
		{
			setcookie(session_name(), '', time()-42000, '/');
		}
		session_destroy();
	}

	/**
    * Reads given session attribute value
    */
	function userdata($item)
	{
		if($item == 'session_id'){ //added for backward-compatibility
			return session_id();
		}else{
			return ( ! isset($_SESSION[$item])) ? false : $_SESSION[$item];
		}
	}

	/**
    * Sets session attributes to the given values
    */
	function set_userdata($newdata = array(), $newval = '')
	{
		if (is_string($newdata))
		{
			$newdata = array($newdata => $newval);
		}

		if (count($newdata) > 0)
		{
			foreach ($newdata as $key => $val)
			{
				$_SESSION[$key] = $val;
			}
		}
	}

	/**
    * Erases given session attributes
    */
	function unset_userdata($newdata = array())
	{
		if (is_string($newdata))
		{
			$newdata = array($newdata => '');
		}

		if (count($newdata) > 0)
		{
			foreach ($newdata as $key => $val)
			{
				unset($_SESSION[$key]);
			}
		}
	}

	/**
    * Starts up the session system for current request
    */
	function _sess_run()
	{
		session_start();

		$session_id_ttl = $this->object->config->item('sess_expiration');

		if (is_numeric($session_id_ttl))
		{
			if ($session_id_ttl > 0)
			{
				$this->session_id_ttl = $this->object->config->item('sess_expiration');
			}
			else
			{
				$this->session_id_ttl = (60*60*24*365*2);
			}
		}

		// check if session id needs regeneration
		if ( $this->_session_id_expired() )
		{
			// regenerate session id (session data stays the
			// same, but old session storage is destroyed)
			$this->regenerate_id();
		}

		// delete old flashdata (from last request)
		$this->_flashdata_sweep();

		// mark all new flashdata as old (data will be deleted before next request)
		$this->_flashdata_mark();
	}

	/**
    * Checks if session has expired
    */
	function _session_id_expired()
	{
		if ( !isset( $_SESSION['regenerated'] ) )
		{
			$_SESSION['regenerated'] = time();
			return false;
		}

		$expiry_time = time() - $this->session_id_ttl;

		if ( $_SESSION['regenerated'] <=  $expiry_time )
		{
			return true;
		}

		return false;
	}

	/**
    * Sets "flash" data which will be available only in next request (then it will
    * be deleted from session). You can use it to implement "Save succeeded" messages
    * after redirect.
    */
	function set_flashdata($key, $value)
	{
		$flash_key = $this->flash_key.':new:'.$key;
		$this->set_userdata($flash_key, $value);
	}

	/**
    * Keeps existing "flash" data available to next request.
    */
	function keep_flashdata($key)
	{
		$old_flash_key = $this->flash_key.':old:'.$key;
		$value = $this->userdata($old_flash_key);

		$new_flash_key = $this->flash_key.':new:'.$key;
		$this->set_userdata($new_flash_key, $value);
	}

	/**
    * Returns "flash" data for the given key.
    */
	function flashdata($key)
	{
		$flash_key = $this->flash_key.':old:'.$key;
		return $this->userdata($flash_key);
	}

	/**
    * PRIVATE: Internal method - marks "flash" session attributes as 'old'
    */
	function _flashdata_mark()
	{
		foreach ($_SESSION as $name => $value)
		{
			$parts = explode(':new:', $name);
			if (is_array($parts) && count($parts) == 2)
			{
				$new_name = $this->flash_key.':old:'.$parts[1];
				$this->set_userdata($new_name, $value);
				$this->unset_userdata($name);
			}
		}
	}

	/**
    * PRIVATE: Internal method - removes "flash" session marked as 'old'
    */
	function _flashdata_sweep()
	{
		foreach ($_SESSION as $name => $value)
		{
			$parts = explode(':old:', $name);
			if (is_array($parts) && count($parts) == 2 && $parts[0] == $this->flash_key)
			{
				$this->unset_userdata($name);
			}
		}
	}
}
?>

Lector RSS de Twitter ideal para Frameworks

| Posted in General |

2

Para un proyecto que estoy desarrollando debía mostrar los últimos X tweets de una cuenta en twitter sin usar JavaScript, sólo PHP; y además debía realizar las labores de “parsing” a las etiquetas # y @ para poder auto-enlazar a su correspondiente query de twitter y además, mostrar “hace cuánto fue escrita la entrada”, es decir: tiempo relativo.

Al no encontrar nada de esto en la web, me dí a la tarea de hacerlo yo mismo, uniendo varias piezas creadas por otros autores incluso en otro lenguajes de programación.

Debo decir que es perfectamente acoplable a cualquier framework en forma de un partial. Puedo decir que corre perfectamente con CodeIgniter.

A continuación, mi humilde aporte:


<?php
/**
 * Visualizar Twitter RSS
 * By: Alexander Garzon (www.php.com.ve)
 * @param string $rss_twitter URL completa del feed RSS
 * @style DIV class named rss_twitter
 * @return html
 */

class RSS_Twitter {

    //Determina si el número (en palabra) es plural si es mayor a 1
    public static function Pluralidad($val, $qty) {
        if ($val > 1) return $val.' '.$qty.'s';
        else return $val.' '.$qty;
    }
    //Calcula el tiempo relativo (diferencia) según una determinada y el presente.
    public static function TiempoRelativo($seconds) {
        if (($seconds / 604800) > 1) return 'Hace '.RSS_Twitter::Pluralidad(round($seconds / 604800), 'semana');
        elseif (($seconds / 86400) > 1) return 'Hace '.RSS_Twitter::Pluralidad(round($seconds / 86400), 'día');
        elseif (($seconds / 3600) > 1) return 'Hace '.RSS_Twitter::Pluralidad(round($seconds / 3600), 'hora');
        elseif (($seconds / 60 ) > 1) return 'Hace '.RSS_Twitter::Pluralidad(round($seconds / 60), 'minuto');
        else return 'Hace '.RSS_Twitter::Pluralidad($seconds, 'segundo');
    }

    public static function FormatoTiempo($tiempocadena) {
        $timestamp = strtotime($tiempocadena);
        $diferencia = time() - $timestamp;
        return RSS_Twitter::TiempoRelativo($diferencia);
    }

    public static function TweetFilter($tweet) {
        //Filtra contenidos del tweet (para links, #tags y @respuestas

        //Se elimina el nmombre del mismo autor en el mensaje (es redundante)
        $pos = strpos($tweet, ":");
        $salida = substr_replace($tweet, '', 0,$pos+2); // El +2 es refiere a el simbolo ':' y el espacio en blanco que le sigue.

        //Agregamos links a los http
        $salida = preg_replace('/(http:\/\/)(.*?)\/([\w\.\/\&amp;amp;\=\?\-\,\:\;\#\_\~\%\+]*)/', '<a href="$0" onclick="window.open(this.href); return false;">$0</a>', $salida);
        //Agregamos links a los @
        $salida = preg_replace('/\B@([_a-zA-Z0-9-]+)/','@<a href="http://twitter.com/$1" onclick="window.open(this.href); return false;">$1</a>',$salida);
        //Agregamos links a los #
        $salida = preg_replace('/\B#([_a-zA-Z0-9-]+)/','<a href="http://search.twitter.com/search?q=%23$1" onclick="window.open(this.href); return false;">#$1</a>',$salida);

        return $salida;

    }
    //Extrae y publica los tweets del RSS
    public static function TweetReader($url) {
        if (!@simplexml_load_file($url)) {
            echo "Error enlazando a Twitter, intente de nuevo";
        } else {
            $feed = simplexml_load_file($url);
            foreach ($feed->channel->item as $item) :
                echo "<div class=\"rss_twitter\">";
                echo $array['title'] = (RSS_Twitter::TweetFilter($item->title))."<br />".PHP_EOL;
                echo "<a href=\"$item->link\" onclick=\"window.open(this.href); return false;\">".RSS_Twitter::FormatoTiempo($item->pubDate)."</a><br />".PHP_EOL;
                echo "<br /></div>".PHP_EOL;
            endforeach;
        }

    }

}

RSS_Twitter::TweetReader($rss_twitter);

?>

Lo único que nos falta es proveer la variable $rss_twitter que corresponde a la ruta absoluta del canal RSS de la cuenta Twitter que deseamos mostrar y además la cantidad de “tweets” que mostraremos, esa ruta viene siendo algo como por ejemplo:

http://twitter.com/statuses/user_timeline/28505702.rss?count=3

Donde 28505702 es el ID de la cuenta de Twitter y 3 es la cantidad de Tweets que mostraremos.

Espero les sea de utilidad.

ACTUALIZACIÓN 12/07/2010: Le he agregado una validación simple para en caso de que por alguna razón Twitter esté caído.

Kohana y CodeIgnitier, los de mayor crecimiento este 2009

| Posted in General |

5

CodeIgnitier y su “fork” Kohana son los 2 frameworks PHP que presentaron el mayor crecimiento según Google trends; mientras los demás muestran un ligero descenso de popularidad.

Inclusive el archi-conocido hijo de Zend, se viene en baja este año.

Ambos son muy buenas opciones para quienes desean programar en PHP sacando partido a los modelos MVC

Integrar Netbeans y CodeIgniter

| Posted in General |

1

No es tan difícil después de todo.

Sólo pones este archivo con cualquier nombre en la raíz del proyecto (codeigniter) y listo.


<?php
/**
 * @property CI_Loader $load
 * @property CI_Form_validation $form_validation
 * @property CI_Input $input
 * @property CI_Email $email
 * @property CI_DB_active_record $db
 * @property CI_DB_forge $dbforge
 * @property CI_Table $table
 * @property CI_Session $session
 * @property CI_FTP $ftp
 * ....
 */
Class Controller {
}
?>

Así de fácil… con esto hemos logrado que el Netbean nos ofrezca en auto-completado, los métodos y variables propias del framework.

Esta técnica puede ser aplicada a otros frameworks, aunque Symfony ya viene integrada como parte de Netbeans.

Autocompletado Codeigniter