API codeigniter

La API esta compuesta por dos librerias: User(se encarga de la autentificación) y Api (que sería el core).

User
User es la libreria encargada de la autenticación. La autenticación se basa en un hash construido por la clave publica y el método al que se llama, y tiene como semilla la clave privada que sólo es conocida por el cliente y el server. La clave pública actúa como identificador de usuario. En este caso he reducido la clase para que sea más entendible.

El hash se genera de la siguiente forma.

hash_hmac("md5",CLAVE_PUBLICA.METODO,CLAVE_PRIVADA)
<?php
class CI_User{

    var $CI;
    var $id = false;
    var $mail = false;
    var $key = array('consumer_public'=>'123','consumer_private'=>'456789');		

    function CI_User() {

        $this->CI = & get_instance();

    }

    function apilogin(){

         if ($this->authapi()) {
           return true;

        } else {

            header('WWW-Authenticate: Basic realm="API eCamina"');
            header('HTTP/1.0 401 Unauthorized');
            echo "Yo can't access. You need auth";
            exit;

        }

    }

    function authapi(){

        if(!isset($_SERVER['PHP_AUTH_USER'])||!isset($_SERVER['PHP_AUTH_PW'])){

           return false;

        }

        $user = $_SERVER['PHP_AUTH_USER'];
        $pass = $_SERVER['PHP_AUTH_PW'];

        if(hash_hmac("md5",$user.$this->CI->uri->segment(2),$this->key['consumer_private']) == $_SERVER['PHP_AUTH_PW']){

            return true;
        }else{
	    return false;
	} 

    }

}

?>

La libreria API recibe los siguientes parametros en la carga:

$list = array('item'=>array('name'=>'roberto','lastanme'=>'Rubio','year'=>'27'),'example'=>array('example'=>'1','example'=>'12125'));

        $config['data'] = $list;
        $config['name'] = MÉTODO;
        $config['error'] = $error;//Boolean;
        $config['type'] = $this->_type(4);//Tipo de los datos a devolver // json o XML.

El array $config es pasado en la carga de la libreria load. A continuación anoto el código de la librería. Básicamente la librería recibe $data que es un array asociativo con los datos a formatear para la salida por pantalla y que depende de los parámetros como type y error. El dato name del array config hace referencia al método que necesitará la autentificación en la librería user.

<?php

defined('BASEPATH') OR exit('No direct script access allowed');

class CI_Api {

    var $data = array();
    var $error = false;
    var $type = 'xml';
    var $typee = array('json', 'xml');
    private $CI;

    function CI_Api($param = false) {
        $data = array();
        $error = true;
        $type = 'xml';
        $name = 'WebService';

        foreach ($param as $key => $val) {

            switch ($key) {
                case 'data': $data = $val;
                    break;
                case 'error': $error = $val;
                    break;
                case 'type': $type = $val;
                    break;
                case 'name': $name = $val;
            }
        }

        $this->name = $name;
        //comprobamos si existe algún error desde la declaración
        $this->error = $error;

        //comprobamos si el array esta vacio
        if (!$this->_set_data($data)) {
            $this->error = true;
        }

        if (!$this->_set_type($type)) {
            $this->error = true;
        }

        if ($this->error) {

            $this->data = array('Error' => 'Error: not found');
        }

        $this->CI = &get_instance();
    }

    function _set_data($value) {

        $ok = false;
        if (count($value) > 0) {
            $this->data = $value;
            $ok = true;
        }

        return $ok;
    }

    //Seteamos el tipò de datos
    function _set_type($value) {

        //comprobamos si el valor esta dentro de los tipos permitidos y guardamos en type
        $ok = false;
        foreach ($this->typee as $t) {
            if ($t == strtolower($value)) {
                $this->type = $value;
                $ok = true;
                break;
            }
        }

        return $ok;
    }

    //devolvemos el error
    function _get_error() {
        return $this->error;
    }

    //devolvemos el tipo pedido
    function _get_type() {
        return $this->type;
    }

    function _get_data() {
        return $this->data;
    }

    function _format() {
        $method = "_get_" . $this->type;
        $this->$method();
    }

    function _get_xml() {

        $xml = new ArrayToXML();
        header('Content-type: text/xml');
        echo $xml->toXml($this->data,$this->name);
    }

    function _get_json() {

        $this->CI->load->library("json");
        header('Content-type: application/json');
        echo json_encode($this->data);
    }

    function get() {

        $this->_format();
    }

}

class ArrayToXML { 

    private $Xml = ''; 

    function __construct() {
    } 

    public function toXml($array, $root = 'data', $numeric_identifier = 'nod'){ 

        $this->Xml .= '<?xml version="1.0" encoding="UTF-8"?>'."\n";
        //$this->Xml .= "<".$root.">\n";
        $this->Xml .= $this->build_xml_tree($array, $numeric_identifier);
        //$this->Xml .= "</".$root.">\n"; 

        return $this->Xml; 

    } 

    public function toXml_echo($array, $root = 'data', $numeric_identifier = 'nod'){ 

        $this->toXml($array, $root, $numeric_identifier);
        echo $this->Xml; 

    } 

    private function build_xml_tree($array, $numeric_identifier){ 

        if(is_array($array)){ 

            $keys = array_keys($array); 

            for($i = 0; $i < sizeof($keys); $i++){ 

                $tag = $keys[$i]; 

                if(is_numeric($tag)){ 

                    $tag = $numeric_identifier; 

                } 

                $this->Xml .= "\t"."<".$tag.">\n"; 

                    $this->build_xml_tree($array[$keys[$i]], $numeric_identifier); 

                $this->Xml .= "\t"."</".$tag.">\n"; 

            } 

        } else if(!empty($array)) {  

            if( $this->checkForHtml($array) ){
                $array = '<![CDATA['.$array.']]>';
            } 

            $this->Xml .= "\t" .$array. "\n"; 

        } else { 

            return false; 

        } 

    } 

    private function checkForHtml($string){ 

        if( strlen($string) != strlen(strip_tags($string)) ){
            return true;
        }
        return false; 

    } 

} ?>

Reflection ingeniería inversa

¿Qué es Reflection?
Reflection es un paradigma de programación que permite conocer como esta construida las clases del código que se esta ejecutanda(ingeniería inversa). PHP tiene una libreria conocida como Reflection(originales!).

Caso de Uso

Imaginate que tenemos una clase cargada tal que así:

class Prueba{
public function saluda(){
return "hola";
}

public function despedida(){
return "adios";
}
}

Una forma de hacerlo sería abrir el fichero donde contenemos la clase y parsearlo para obtener sus métodos pero esto es poco elegante y puede que nos de más de un dolor de cabeza sin contar con cambios en las clases.

Con Reflection podríamos realizar las siguiente lectura:

  $class = new ReflectionClass("Prueba");
$metodos=$class-&gt;getMethods(); // $metodo contendrá un array con los métodos de nuestra clase.

Ojo tendríamos que tener cargado la clase en nuestra clase para hacer uso de ella. Puedes utilizar el método require();

Librería para implentar client XMPP

Estaba desarrollado un chat para el helpdesk de la empresa y empecé a buscar script PHP de chats para la implementación dentro de la aplicación. Después analicé mi necesidades y comprendí lo improductivo de tener una aplicación web para el contacto con el usuario. Yo soy usuario de gtalk así que me decidí por implementar un helpdesk que interactuara con Gtalk y que los mensajes del usuario se remitieran a mi usuario. Buscando encontré esta interesante librería para gestionar comunicación mediante el protocolo XMPP.  Este protocolo es el más extendido por la mayoría de aplicaciones de mensajería instantánea así que si no te convence trabajar con gtalk puedes utilizarla para muchos otros(facebook, ICQ, MSN…) o  incluso  implantar en un server XMPP.

links how do to make a API’s?

Autenticación oAuth
http://code.google.com/p/oauth-php/
http://php.net/manual/en/book.oauth.php
http://oauth.net/code/

Tutoriales para la API
http://particletree.com/features/how-to-add-an-api-to-your-web-service/
http://blog.realmofzod.com/blog/2009/05/06/implement-a-rest-api-with-the-zend-framework/
http://jasonirwin.ca/2009/05/24/simple-api/
http://www.recessframework.org/page/towards-restful-php-5-basic-tips
http://www.gen-x-design.com/archives/making-restful-requests-in-php/
http://www.gen-x-design.com/archives/create-a-rest-api-with-php/
adlemons

OpenLlavor y el conomiento universal

Durante mucho tiempo hemos estado debatiendo, hablando y pensando como empezar con el movimiento. En un principio creíamos que deberíamos empezar dando cursos de formación de forma voluntaria y gratuita, y quizas dentro de un tiempo poder montar una escuela de startup. Pero parece un poco difícil comenzar, dar a conocer la idea y sobretodo que la gente se implique participando. Por esta razón pensé que lo primero que debíamos de realizar es un evento sobre PHP, que la verdad aquí en Valencia no hay. Es una forma de conocer a gente con las mismas inquietudes, que al fin y al cabo son potenciales socios.

Total que parece que la idea a gustado entre algunos del PCUV (Parc Científic de la Universitat de València) y se va a crear. Es el primer acto que va a estar impulsado por la asociación y se llama Jornada PHP valencia.

Este evento se celebrará el próximo 28 de Enero en Valencia, con entrada gratuita y donde se reunirán grandes ponentes del sector del desarrollo mostrando casos de éxito y como ven ellos el futuro de la programación en PHP. Y sobretodo para vernos las caras y desvirtualizarnos, que también es importante. Es un foco de búsqueda de trabajo por que nos consta que existe empresas que están buscando programadores para sus proyectos y están invitadas.

Por cierto la asociación se llama OpenLlavor, llavor es semilla en Valenciano.

checkbox checked Jquery

Para introducir los valores de los checkbox seleccionados y que pertenezcan a la misma clase.

var n;
var categories = new Array();

$(“.categories:checked”).each(function(){

categories[n] = $(this).val();
n++;

});

De esta forma tendremos todos los valores chequeados. Una vez obtenidos sólo quedaría tratarlos a gusto del consumidor. Yo como normal general suelo comprobar los datos tanto en el cliente como en el server, pero vamos que lo podeis hacer desde el server y ahorraros la faena del javascript.

Me gusta más esta forma de programar más dinámica que darle a cada checkbox un id distinto ( Recordar que el Id no se puede repetir para todos lo elementos de una misma web, pero si la clase y el name).

Tweetsfeed.org: Lector de feed para twitter

Tweetsfeed.org es un lector de feed que te permite sindicarte a todos los blogs que quieras mediante instrucciones desde twitter. La aplicación te envia los nuevos post de los blogs como mensajes privados a twitter.

A continuación listo las instrucciones básicas para trabajar con esta herramienta:

1) @tweetsfeed http://www.example.com/feed
//Esta instrucción te permite sindicarte a un blog
2) @tweetsfeed -R http://www.example.com/feed
//Esta instrucción te permite deshacer la sindicación
3) @tweetsfeed -d [http://www.example.com/feed]
//Esta instrucción permite al usuario desactivar la recepción de feeds. Si -d no lleva ningún feed por defecto desactiva el envio de feeds. Si está acompañado de feed desactiva el envio de feeds de ese blog.
4) @tweetsfeed -a [http://www.example.com/feed]
//Permite activar el envio de feeds. Si no esta acompañado de ninguna dirección de feed se considera que activas la recepción de todos los feeds.

* [ ] opcional.
Para la recepción de feeds debes ser follower del usuario @tweetsfeed.

La paginación en codeigniter sin condiciones

El titulo quizás sea muy retórico para hablar de temas técnicos.  LLevo unos meses trabajando bastante con Codeigniter. Hasta ahora nos ha ido de lujo, pero de vez en cuando cojea, no todo puede ser perfecto. Nos hemos dado cuenta, dentro del equipo de desarrollo de Adlemons.com, que codeigniter, almenos con la versión que trabajamos, tiene serios problemas con la librería de paginación,  la cual no te permite combinar filtros en las búsquedas.

Nosotros hemos solucionado el problema con javascript, php y mucha imaginación, ya que  el entorno donde se originaba el problema permitía tomarse la licencia de pasarse la parte SEO por el arco del triunfo y hacerlo todo de forma dinámica con Objetos Ajax.

Hemos creado una librería apodada “paginations.php” ( muy originales teniendo en cuenta que la primitiva de codeigniter es pagination) que recoje unos parámetros, entre ellos el nombre de la función que actualiza el div con nueva página y la cual devuelve los links de pagination con el formato adecuado haciendo referencia a la función de javascript que actualiza el div del resultado de la búsqueda. Acontinuación voy a anotar como utilizamos la librería paginations.php:

Qué cambios se ha realizado en la librería pagination.php para llamarse paginations.php?
antes

$output .= $this->num_tag_open.'".$loop."".$this->num_tag_close;

después

$output .= $this->num_tag_open."base_url."('.$n.'); ">".$loop."".$this->num_tag_close;

El secreto reside en la lamada en el href del vinculo a la función javascript que refresca el DIV.

antes

$this->base_url = rtrim($this->base_url, '/') .'/';

después

$this->base_url = rtrim($this->base_url, '') .''; // evitas que ponga una barra invertida detrás

Así se utiliza:

1º introducimos los parámetros $this->load->library(‘paginations’);

$config['base_url'] = 'update'//es el nombre de la funcion javascript que llama

$config['total_rows'] = 'Numero de elementos a filtrar';

$config['per_page'] = 'elementos por páginas a mostrar';

$config['uri_segment'] = 'Segmento de la url que contiene el número de paginación';

$this->paginations->initialize($config); // Inicializamos

//Está función devuelve la cadena string con formato HTML con los elementos de la páginación << < 1 2 3 4 5 > >>

$parapasaravista=$this->paginations->create_links();

Y en la vista tengo una función, en este caso llamada ‘update’ , en ajax que refresca el DIV con los filtros creados.

La importancia del I+D

Todas la empresas de tecnología deberían, como hace google, permitir a sus trabajador exprimir su originalidad y creatividad a la hora de crear contenido, webs o chorradas varias. Mi empresa tiene esa filoofía dentro de sus limitadas posibilidades.

Hoy navegando por unos comentarios puestos en facebook he visto uno mio, de los que no te acuerdas de haber publicado. En él se anunciaba la posibilidad de descargar RAM. Si si, RAM. Así que me dispuse a crear mi acelerador de tarjeta gráfica bautizado como KTNT. Si quereis probarlo solo teneis que ir aquí.

El debate de Geonio.com

Siempre he querido colaborar en la comunidad Opensource, que tanto nos ha dado, con un pequeño grano de arena. Así que he decidido poner Geonio en licencia GPL.

Para comenzar en este proceso he decidido, empezar de cero otra vez, pero esta vez con un framework. Primero empece buscando por la red documentación para elegir el framework que necesitaba de acuerdo a las características de Geonio.com. Mi primera opción fue CakePHP, lo instalé comence a implementar código. Me convencio su gran comunidad de desarrolladores. Pero empeze a darme cuenta que el software era demasiado extenso y tienen tropecientasmil cosas potentes pero con procesos demasiado costosos. Así que alfinal me hice con codeigniter que es mucho más ligero y simple, permitiendote realizar cualquier tipo de desarrollo sin depender de él sistematicamente.

Acabo de empezar a reusar el código que tenia migrándolo a codeigniter, reusando vistas, modificando controladores y creando los modelos nuevos por cambios en E-R de la Mysql.

Si quereis tener acceso al código solo teneis que ir aquí. Pd: no os asusteis que está en fase ALPHA ;) .