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; 

    } 

} ?>

Cart de codeigniter y 10 articulos

Imáginate un mundo donde no puedieras comprar más de 10 articulos. Pues bien es un caso muy tonto pero se da en codeigniter. Si comenzastes el proyecto web con la versión 1.03 de este framework y querías utilizar el librería Cart de codeigniter no podrías añadir al carrito más de 10 elementos. Es un error más común de lo que parece, el truco consiste en que la versiones anteriores de codeigniter venían con una base de datos con una tabla con diferencias, a las versiones más nuevas. En la tabla ci_session, la encargada de recoger valores de sesión y cookie, es muy diferente (bueno quizás no tanto) a las versiones nuevas. Sólo debes actualizar esta tabla y te funcionará perfecto.

CREATE TABLE IF NOT EXISTS `ci_sessions` (
session_id varchar(40) DEFAULT ’0′ NOT NULL,
ip_address varchar(16) DEFAULT ’0′ NOT NULL,
user_agent varchar(50) NOT NULL,
last_activity int(10) unsigned DEFAULT 0 NOT NULL,
user_data text NOT NULL,
PRIMARY KEY (session_id)
);

Pero vamos que si lees elmanual de codeigniter lo verás ;)

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.

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 ;) .

Codeigniter: An Error Was Encountered The URI you submitted has disallowed characters.

Sin querer actualicé mi versión de PHP y me surgierona algunos problemas con las URI y los carácteres especiales, que se resuelven así:

Necesitas sustituir la línea:

if(!preg_match("|^[". preg_quote($this->config->item('permitted_uri_chars'))."]+$|i", rawurlencode($str)))

por

if(!preg_match("|^[".($this->config->item('permitted_uri_chars'))."]+$|i", rawurlencode($str)))

en el archivo URI.php del libraries de Codeigniter y cambiar en el config.php de la configuración del proyecto los carácteres aceptados para la URL:
antes
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_-';

ahora

$config['permitted_uri_chars'] = 'a-z 0-9~%\.\:_\-';
.
Espero que tengais suerte. Saludos.