Mostrando entradas con la etiqueta CodeIgniter. Mostrar todas las entradas
Mostrando entradas con la etiqueta CodeIgniter. Mostrar todas las entradas

miércoles, 24 de julio de 2013

Codeigniter 2: cómo insertar multiples filas en una tabla

Insertar múltiples filas en CodeIgniter 2, útil para manejadores como MySQL y PostgreSQL

Este artículo lo tomé de http://codefury.net/2009/12/insert-multiple-rows-into-a-database-with-codeigniter/, pero lo he adaptado para funcionar con CI2

Paso 1: Extender la clase Model.php

En la carpeta application/core/ crear la clase MY_Model.php, el prefijo MY_ debe ser el mismo que se encuentra establecido en el archivo config.php en el elemento 'subclass_prefix'

<?php

/**
 * @link http://codefury.net/2009/12/insert-multiple-rows-into-a-database-with-codeigniter/ Hacer multiples inserts
 * @author KENNY KATZGRAU
 */
class MY_Model extends CI_Model
{

    public function __construct()
    {
        parent::__construct();
    }

    /**
     * A method to facilitate easy bulk inserts into a given table.
     * @param string $table_name
     * @param array $column_names A basic array containing the column names of the data we'll be inserting
     * @param array $rows A two dimensional array of rows to insert into the database.
     * @param bool $escape Whether or not to escape data that will be inserted. Default = true. Para otros drivers diferentes a MySQl, habría que poner FALSE
     * @author Kenny Katzgrau 
     */
    public function insert_rows($table_name, $column_names, $rows, $escape = true)
    {
        /* Build a list of column names */
        $columns = array_walk($column_names, array($this, 'prepare_column_name'));
        $columns = implode(',', $column_names);

        /* Escape each value of the array for insertion into the SQL string */
        if ($escape){
            array_walk_recursive($rows, array($this, 'escape_value'));
        }
        
        # asignar un table-prefix si está definido en el archivo database.php
        $table_name = $this->db->dbprefix($table_name);

        /* Collapse each rows of values into a single string */
        $length = count($rows);
        for ($i = 0; $i < $length; $i++){
            $rows[$i] = implode(',', $rows[$i]);
        }

        /* Collapse all the rows into something that looks like
         *  (r1_val_1, r1_val_2, ..., r1_val_n),
         *  (r2_val_1, r2_val_2, ..., r2_val_n),
         *  ...
         *  (rx_val_1, rx_val_2, ..., rx_val_n)
         * Stored in $values
         */
        $values = "(" . implode('),(', $rows) . ")";

        $sql = "INSERT INTO {$table_name} ({$columns}) VALUES {$values}";
        
        /*
        $querie_file = PATH_APP_DEBUGS . 'queries_' . date('Y-m-d') . '.log';
        file_put_contents($querie_file, $sql, FILE_APPEND);
         * 
         */

        return $this->db->simple_query($sql);
    }

    public function escape_value(& $value)
    {
        if (is_string($value)) {
            $value = "'" . mysql_real_escape_string($value) . "'";
        }
    }

    public function prepare_column_name(& $name)
    {
        $name = "`$name`";
    }

}

Paso 2: Ejemplo A

He aquí un ejemplo para probar la inserción de varias filas en un mismo query:

class Messages extends MY_Model 
{   
  /* Code .. */   
  function insert_test_data()   
  {     
    /* Prepare some fake data (10000 rows, 40,000 values total) */
    $rows = array_fill(0, 10000, array(34239, 102438, "Test Message!", '2009-12-12'));
    $columns = array('to_user_id', 'from_user_id', 'message', 'created');
    $this->insert_rows('messages', $columns, $rows); 
  }
}

Paso 1: Ejemplo B

Otro ejemplo, de cómo se usaría en un método típico de un modelo en CodeIgniter:

<?php

class M_usuarios extends MY_Model
{

    private $_enc_key;
    protected $_usuario_id;

    public function asignar_permisos()
    {
        $this->_usuario_id = (int) $this->input->post('sel_campo01');
        $this->db
                ->where('usuario_id', $this->_usuario_id)
        ;
        try {
            $this->db->trans_start();

            $this->db->query('LOCK TABLES t_ci_sessions LOW_PRIORITY WRITE');
            $this->db->query('LOCK TABLES t_usuarios_t_submenus LOW_PRIORITY WRITE');

            # primero, eliminar todos los permisos asignados
            $delete = $this->db->delete('usuarios_t_submenus');

            # segundo, insertar todos los permisos recién asignados
            $a_columns = array('usuario_id', 'submenu_id');
            $a_rows = $this->_preparar_datos_permisos($this->_usuario_id, $this->input->post('sel_campo02'));

            # método insert_rows() que nosotros definimos en la clase MY_Model.php
            $insert = $this->insert_rows('usuarios_t_submenus', $a_columns, $a_rows);
            
            $this->db->query('UNLOCK TABLES');
            $this->db->trans_complete();
            
            return array('insert' => TRUE, 'mensaje' => '');
        } catch (Exception $e) {
            $this->db->query('UNLOCK TABLES');
            $this->db->trans_complete();

            return array('insert' => FALSE, 'mensaje' => $e->getMessage());
        }
    }

    private function _preparar_datos_permisos($usuario_id, $permisos)
    {
        $filas = array();
        foreach ($permisos as $_submenu_id){
            $filas[] = array($usuario_id, $_submenu_id);
        }
        
        return $filas;
    }
}

Eso es todo, espero que les sea de utilidad.

miércoles, 10 de julio de 2013

Encriptar y desencriptar cadenas con PHP

Crear una función para encriptar - desencriptar (encrypting two way) usando PHP

Útil para enmascarar urls, variables por post, get, datos, números de tarjetas de crédito, etc.

Puedes usarla para programación scriptera, orientada a objetos, como helper en algún framework, tales como CodeIgniter, Zend, Cake, Yii, etc.

Bueno, aquí vamos:

<?php
function _enc($s)
{
    $str = (string) $s;
    
    if ('' == trim($str)) {
        return '';
    }
    for ($i = 0; $i < strlen($str); $i++) {
        $r[] = hexdec(decoct(ord($str[$i]) + 3));
    }

    return implode(',', $r);
}

function _dec($s)
{
    $str = (string) $s;
    
    if ('' == trim($str)) {
        return '';
    }
    $s = explode(',', $str);
    for ($i = 0; $i < count($s); $i++) {
        $s[$i] = chr(octdec(dechex($s[$i])) - 3);
    }

    return implode('', $s);
}
?>

El artículo original de este código viene desde www.hawkee.com/snippet/5086/, yo le añadí doble cifrado, uno en octal y el resultado obtenido lo paso a hexadecimal, esto lo hice porque si lo dejaba en decimal es bien fácil encontrar que los caracteres corresponden a códigos ASCII y cualquiera podría descifrar el contenido.

Espero les sea de utilidad.

jueves, 27 de junio de 2013

Cómo crear un sitemap con CodeIgniter 2 para enviarlo a Google Webmasters Tools

Para crear un sitemap en formato xml con CodeIgniter 2, para enviarlo a google, necesitamos de los siguientes pasos.

Paso 1: Modificar el archivo routes.php, ubicado en la carpeta config

El cual se encuentra en la carpeta config/. Agregamos una nueva línea al arreglo:

            $route['sitemap.xml'] = 'sitemap/index';
        

Paso 2: Crearemos entonces el controlador sitemap.php

            <?php

            class Sitemap extends CI_Controller
            {

                public function __construct()
                {
                    parent::__construct();
                }

                public function index()
                {
                    # este helper se puede cargar en el archivo autoload.php
                    # para evitar cargarlo cada vez
                    $this->load->helper('url');

                    $this->load->model('sitemap_model');

                    $view_data['vw_content'] = $this->sitemap_model->get_articulos();

                    $this->load->view('sitemap_view', $view_data);
                }

            }
        

Paso 3: Creamos el modelo sitemap_model.php

            <?php

            class Sitemap_model extends CI_Model
            {

                public function __construct()
                {
                    parent::__construct();

                    # esta librería se puede cargar desde el archivo autoload.php
                    # para evitar cargarlo cada vez
                    $this->load->database();
                }

                public function get_articulos()
                {
                    $this->db
                            ->select('articulo_id, alias, modificado')
                            ->from('articulos')
                            ->where('activo', 1)
                            ->order_by('articulo_id')
                    ;

                    $query = $this->db->get();

                    return $query->result();
                }

            }
        

En nuestro ejemplo, vamos a suponer que la estructura de la tabla es como la siguiente:

Paso 4: Creamos la vista sitemap_view.php

            <?php ob_start(); ?>
            <?php echo '<?xml version="1.0" encoding="UTF-8"?>'."\n"; ?>
            <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
                <url>
                    <loc><?php echo base_url(); ?></loc>
                    <priority>1.0</priority>
                </url>

                <!-- Sitemap de mi blog.com -->
                <?php foreach ($vw_content as $url) : ?>
                <url>
                    <loc><?php echo base_url() . 'index.php/blog/articulos/' . $url->articulo_id . '/' . $url->alias . '/'; ?></loc>
                    <lastmod><?php echo substr($url->modificado, 0, 10); ?></lastmod>
                    <changefreq>monthly</changefreq>
                    <priority>0.5</priority>
                </url>
                <?php endforeach; ?>
            </urlset>
            <?php ob_end_flush(); ?>
        

Paso 5: Probar tu sitemap ejecutando (por ejemplo) http://localhost/ci2/index.php/sitemap.xml

¡Listo! Si todo salió bien pueder ver el codigo fuente generado y verás un archivo .xml bien formado, el cual estará listo para enviarlo a Google en su página de herramientas para Webmasters.

viernes, 17 de mayo de 2013

CodeIgniter 2: Implementar mecanismo de idiomas para tus aplicaciones PHP

CodeIgniter 2 trae su propio sistema de regionalización de idiomas, pero francamente me parece poco práctico, pues se basa en crear arreglos asociativos con las diferentes cadenas de traducción, el problema de esta técnica es que se requiere consultar constantemente el archivo de configuración para ver el nombre de la llave del arreglo y poder obtener la cadena, en cambio, sugiero usar un sistema más parecido al que usa Magento, que traduce la cadena en función de la cadena misma, y utiliza un sencillo sistema de archivos separados por comas y en pares.

Así que los pasos para implementar un sistema de regionalización de idiomas son:

Paso 1.

Crear en la carpeta application/language/, los diferentes códigos de idiomas, en mi caso, utilzaré en_US/ y es_MX/

Paso 2.

Nuestra base siempre va a ser el inglés de estados unidos, así que vamos a crear en la carpeta en_US un archivo llamado core_general.csv

Paso 3.

Es importante señalar que uno puede organizar los archivos de idiomas según su ámbito, por ejemplo, podemos crear uno llamado core_exceptions.cvs, otro para core_database.csv, otro para sales.csv, otro para checkout.csv, otro crm.csv, etc.

Paso 4.

La técnica es usar los archivos separados por comas en pares: tal como se muestra el ejemplo, recordemos que la base es el idioma inglés de E.U., en este ejemplo te muestro los dos archivos, el que colocaremos en la carpeta en_US/ y el que colocaremos en la carpeta es_MX/, con esto ya se va comprendiendo más la lógica:

en_US/core_general.csv

"ERP","ERP"
"MRP","MRP"
"CRM","CRM"
"FRM","FRM"
"HRM","HRM"
"SCM","SCM"
"Enterprise Resource Planning","Enterprise Resource Planning"
"Material Resource Planning","Material Resource Planning"
"Customer Relationship Management","Customer Relationship Management"
"Financial Resource Management","Financial Resource Management"
"Human Resource Management","Human Resource Management"
"Supply Chain Management","Supply Chain Management"
"Inbox","Inbox"
"Personal","Personal"
"Important","Important"
"Pending","Pending"
"Archived","Archived"
"archived","archived"
"Schedule","Schedule"
"Calendar","Calendar"
"Notes","Notes"
"Groups","Groups"
"Messages","Messages"
"Create/Join Groups","Create/Join Groups"
"Go!","Go!"
"Search...","Search..."
"Edit Profile","Edit Profile"
"View Profile","View Profile"
"View All","View All"
"Logout","Logout"
"Login","Login"
"",""
"",""
"",""
"",""
"",""
"",""

es_MX/core_general.csv

"ERP","PRE"
"MRP","PRM"
"CRM","GAC"
"FRM","GRF"
"HRM","GRH"
"SCM","GCS"
"Enterprise Resource Planning","Planificación de recursos empresariales"
"Material Resource Planning","Planificación de recursos materiales"
"Customer Relationship Management","Gestión de atención al cliente"
"Financial Resource Management","Gestión de recursos financieros"
"Human Resource Management","Gestión de recursos humanos"
"Supply Chain Management","Gestión de la cadena de suministro"
"Inbox","Bandeja de entrada"
"Personal","Personal"
"Important","Importante"
"Pending","Pendiente"
"Archived","Archivados"
"archived","archivados"
"Schedule","Agenda"
"Calendar","Calendario"
"Notes","Notas"
"Groups","Grupos"
"Messages","Mensajes"
"Create/Join Groups","Crear/Unir grupos"
"Go!","Ir..."
"Search...","Buscar..."
"Edit Profile","Modificar perfil"
"View Profile","Ver perfil"
"View All","Ver todo"
"Logout","Desconectar"
"Login","Conectar"
"",""
"",""
"",""
"",""
"",""
"",""

Paso 5.

Ahora, vamos a crear un helper, llamado translate_helper.php y lo vamos a colocar en la carpeta application/helpers/

<?php

/**
 * Regresa una cadena con la traducción especificada.
 * Si se especifica $code, se regresa la cadena en ese idioma, 
 * si no se envía el parámetro opcional $code, entonces la 
 * cadena es regresada en el idioma especificado en el archivo 
 * config.php de CI.
 * 
 * @param string $texto La cadena a traducir
 * @param string $archivo El archivo de traducción, por default, el core_general.csv
 * @param string $codigo El código idioma_región, pe: es_MX
 * @return string
 */
function __($texto, $archivo = 'core_general', $codigo = NULL)
{
    $texto_str = (string) $texto;

    # validar si la cadena viene vacía
    if ('' == $texto_str) {
        return '';
    }

    # quitar espacios a la cadena
    $texto_ok = trim($texto);

    # inicializar locale por si no se encuentra la cadena a traducir
    $text_locale = $texto_ok;

    # validar código de idiomas
    if (!is_string($codigo)) {
        $codigo = config_item('locale_default');
    } else {
        $valid_code = array_search($codigo, config_item('locale_list'));

        # si el código locale no está en la lista de paquetes de idioma disponibles,
        # entonces, tomar el default.
        if (FALSE === $valid_code) {
            $codigo = config_item('locale_default');
        }
    }

    $archivo = PATH_RAIZ . URL_ROOT_FOLDER . APPPATH . DIR_LANG . $codigo . '/' . $archivo . '.csv';

    try {
        $handle = @fopen($archivo, 'rb');
    } catch (Exception $e) {
        return $text_locale;
    }
    
    if (FALSE !== $handle) {
        while (FALSE !== ($data = fgetcsv($handle, 1000, ','))) {
            if ($texto_ok == $data[0]) {
                $text_locale = $data[1];
                break;
            }
        }
        fclose($handle);
    }

    return $text_locale;
}

/*  EOF  */

Paso 6.

Ahora necesitamos crear unas constantes, así que editamos el archivo application/config/constants.php y declaramos las siguientes constantes:

define('PATH_RAIZ', $_SERVER['DOCUMENT_ROOT'] . '/');
define('URL_ROOT_FOLDER', ''); // si tu aplicación corre desde un(os) subdirectorio(s), ponerlo aquí por ejemplo: define('URL_ROOT_FOLDER', 'misubfolder/');
define('DIR_LANG', 'language/');

Paso 7.

Editamos el archivo application/config/autoload.php y agregamos el nuevo helper (translate) a la lista, en mi ejemplo se vería así:

$autoload['helper'] = array('url', 'form', 'directory', 'file', 'html', 'date', 'cookie', 'translate');

Paso 8.

En el mismo archivo autoload.php debemos colocar en una sección llamada "Auto-load config files", lo siguiente:

/*
| -------------------------------------------------------------------
|  Auto-load Config files
| -------------------------------------------------------------------
| Prototype:
|
| $autoload['config'] = array('config1', 'config2');
|
| NOTE: This item is intended for use ONLY if you have created custom
| config files.  Otherwise, leave it blank.
|
*/

$autoload['config'] = array('locale');

Paso 9.

Ahora debemos crear el archivo de configuración locale.php en la carpeta application/config/ y colocamos el siguiente contenido:

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

$config['locale_default'] = 'es_MX';

//$config['locale_list'] = array('en_US', 'en_GB', 'es_ES', 'es_AR', 'es_CL', 'es_MX', 'es_UY', 'es_VE', 'fr_FR', 'pt_BR');

# idiomas disponibles, en mi caso, solamente manejaré éstos dos:
$config['locale_list'] = array('en_US', 'es_MX');

/* EOF */

Paso 10.

Listo, ahora ya estamos preparados para usar nuestro archivo de traducciones en cualquier tipo de script: vista, controlador, modelo, helpers, librerías, etc., aquí un ejemplo para usarlo en una vista:

<ul>
    <li class="admin-username"><?php echo $username; ?></li>
    <li><a href="#"><?php echo __('Edit Profile'); ?></a></li>
    <li><a href="#"><?php echo __('View Profile'); ?></a><a href="#"><i class="icon-lock"></i><?php echo __('Logout'); ?

></a></li>
    <li class="active"><a href="#messages" class="icon-inbox" title="<?php echo __('Messages'); ?>"></a></li>
    <li><a href="#schedule" class="icon-calendar" title="<?php echo __('Schedule'); ?>"></a></li>
    <li><a href="#groups" class="icon-group" title="<?php echo __('Groups'); ?>"></a></li>
</ul>

11. Por último, las variantes para este helper, serían por ejemplo:

__('String to translate', 'sales'); // usar el archivo sales.csv
__('String to translate', 'sales', 'fr_FR'); // usar el archivo sales.csv y además forzar a usar el idioma francés de Francia.

Espero que le sea de utilidad.

jueves, 16 de mayo de 2013

Convertir números a letras con CodeIgniter 2, usando ajax y jQuery

Es la misma función que hice para convertir números a letras, pero ahora integrada a CodeIgniter 2

como un valor adicional, vamos a hacer la llamada por ajax usando jQuery, pero lo que realmente vale es el helper que hace la conversión de números a letras

Para este ejemplo voy a suponer que ya conoces las bases de CodeIgniter, de lo contrario sugiero primero ir a la documentación oficial: http://escodeigniter.com/guia_usuario/

Puedes ejecutar el demo desde aquí Convertir números a letras PHP con CodeIgniter 2

El código fuente lo puedes descargar desde aquí numeros_a_letras_CI2.zip

Primero, creamos un helper

<?php

/**
 * Convierte un número en una cadena de letras, para el idioma
 * castellano, pero puede funcionar para español de mexico, de  
 * españa, colombia, argentina, etc.
 * 
 * Máxima cifra soportada: 18 dígitos con 2 decimales
 * 999,999,999,999,999,999.99
 * NOVECIENTOS NOVENTA Y NUEVE MIL NOVECIENTOS NOVENTA Y NUEVE BILLONES
 * NOVECIENTOS NOVENTA Y NUEVE MIL NOVECIENTOS NOVENTA Y NUEVE MILLONES
 * NOVECIENTOS NOVENTA Y NUEVE MIL NOVECIENTOS NOVENTA Y NUEVE PESOS 99/100 M.N.
 * 
 * @author Ultiminio Ramos Galán <contacto@ultiminioramos.com>
 * @param string $numero La cantidad numérica a convertir 
 * @param string $moneda La moneda local de tu país
 * @param string $subfijo Una cadena adicional para el subfijo
 * 
 * @return string La cantidad convertida a letras
 */
function num_to_letras($numero, $moneda = 'PESO', $subfijo = 'M.N.')
{
    $xarray = array(
        0 => 'Cero'
        , 1 => 'UN', 'DOS', 'TRES', 'CUATRO', 'CINCO', 'SEIS', 'SIETE', 'OCHO', 'NUEVE'
        , 'DIEZ', 'ONCE', 'DOCE', 'TRECE', 'CATORCE', 'QUINCE', 'DIECISEIS', 'DIECISIETE', 'DIECIOCHO', 'DIECINUEVE'
        , 'VEINTI', 30 => 'TREINTA', 40 => 'CUARENTA', 50 => 'CINCUENTA'
        , 60 => 'SESENTA', 70 => 'SETENTA', 80 => 'OCHENTA', 90 => 'NOVENTA'
        , 100 => 'CIENTO', 200 => 'DOSCIENTOS', 300 => 'TRESCIENTOS', 400 => 'CUATROCIENTOS', 500 => 'QUINIENTOS'
        , 600 => 'SEISCIENTOS', 700 => 'SETECIENTOS', 800 => 'OCHOCIENTOS', 900 => 'NOVECIENTOS'
    );

    $numero = trim($numero);
    $xpos_punto = strpos($numero, '.');
    $xaux_int = $numero;
    $xdecimales = '00';
    if (!($xpos_punto === false)) {
        if ($xpos_punto == 0) {
            $numero = '0' . $numero;
            $xpos_punto = strpos($numero, '.');
        }
        $xaux_int = substr($numero, 0, $xpos_punto); // obtengo el entero de la cifra a covertir
        $xdecimales = substr($numero . '00', $xpos_punto + 1, 2); // obtengo los valores decimales
    }

    $XAUX = str_pad($xaux_int, 18, ' ', STR_PAD_LEFT); // ajusto la longitud de la cifra, para que sea divisible por centenas de miles (grupos de 6)
    $xcadena = '';
    for ($xz = 0; $xz < 3; $xz++) {
        $xaux = substr($XAUX, $xz * 6, 6);
        $xi = 0;
        $xlimite = 6; // inicializo el contador de centenas xi y establezco el límite a 6 dígitos en la parte entera
        $xexit = true; // bandera para controlar el ciclo del While
        while ($xexit) {
            if ($xi == $xlimite) { // si ya llegó al límite máximo de enteros
                break; // termina el ciclo
            }

            $x3digitos = ($xlimite - $xi) * -1; // comienzo con los tres primeros digitos de la cifra, comenzando por la izquierda
            $xaux = substr($xaux, $x3digitos, abs($x3digitos)); // obtengo la centena (los tres dígitos)
            for ($xy = 1; $xy < 4; $xy++) { // ciclo para revisar centenas, decenas y unidades, en ese orden
                switch ($xy) {
                    case 1: // checa las centenas
                        $key = (int) substr($xaux, 0, 3);
                        if (100 > $key) { // si el grupo de tres dígitos es menor a una centena ( < 99) no hace nada y pasa a revisar las decenas
                            /* do nothing */
                        } else {
                            if (TRUE === array_key_exists($key, $xarray)) {  // busco si la centena es número redondo (100, 200, 300, 400, etc..)
                                $xseek = $xarray[$key];
                                $xsub = subfijo($xaux); // devuelve el subfijo correspondiente (Millón, Millones, Mil o nada)
                                if (100 == $key) {
                                    $xcadena = ' ' . $xcadena . ' CIEN ' . $xsub;
                                } else {
                                    $xcadena = ' ' . $xcadena . ' ' . $xseek . ' ' . $xsub;
                                }
                                $xy = 3; // la centena fue redonda, entonces termino el ciclo del for y ya no reviso decenas ni unidades
                            } else { // entra aquí si la centena no fue numero redondo (101, 253, 120, 980, etc.)
                                $key = (int) substr($xaux, 0, 1) * 100;
                                $xseek = $xarray[$key]; // toma el primer caracter de la centena y lo multiplica por cien y lo busca en el arreglo (para que busque 100,200,300, etc)
                                $xcadena = ' ' . $xcadena . ' ' . $xseek;
                            } // ENDIF ($xseek)
                        } // ENDIF (substr($xaux, 0, 3) < 100)
                        break;
                    case 2: // checa las decenas (con la misma lógica que las centenas)
                        $key = (int) substr($xaux, 1, 2);
                        if (10 > $key) {
                            /* do nothing */
                        } else {
                            if (TRUE === array_key_exists($key, $xarray)) {
                                $xseek = $xarray[$key];
                                $xsub = subfijo($xaux);
                                if (20 == $key) {
                                    $xcadena = ' ' . $xcadena . ' VEINTE ' . $xsub;
                                } else {
                                    $xcadena = ' ' . $xcadena . ' ' . $xseek . ' ' . $xsub;
                                }
                                $xy = 3;
                            } else {
                                $key = (int) substr($xaux, 1, 1) * 10;
                                $xseek = $xarray[$key];
                                if (20 == $key)
                                    $xcadena = ' ' . $xcadena . ' ' . $xseek;
                                else
                                    $xcadena = ' ' . $xcadena . ' ' . $xseek . ' Y ';
                            } // ENDIF ($xseek)
                        } // ENDIF (substr($xaux, 1, 2) < 10)
                        break;
                    case 3: // checa las unidades
                        $key = (int) substr($xaux, 2, 1);
                        if (1 > $key) { // si la unidad es cero, ya no hace nada
                            /* do nothing */
                        } else {
                            $xseek = $xarray[$key]; // obtengo directamente el valor de la unidad (del uno al nueve)
                            $xsub = subfijo($xaux);
                            $xcadena = ' ' . $xcadena . ' ' . $xseek . ' ' . $xsub;
                        } // ENDIF (substr($xaux, 2, 1) < 1)
                        break;
                } // END SWITCH
            } // END FOR
            $xi = $xi + 3;
        } // ENDDO
        # si la cadena obtenida termina en MILLON o BILLON, entonces le agrega al final la conjuncion DE
        if ('ILLON' == substr(trim($xcadena), -5, 5)) {
            $xcadena.= ' DE';
        }

        # si la cadena obtenida en MILLONES o BILLONES, entonces le agrega al final la conjuncion DE
        if ('ILLONES' == substr(trim($xcadena), -7, 7)) {
            $xcadena.= ' DE';
        }

        # depurar leyendas finales
        if ('' != trim($xaux)) {
            switch ($xz) {
                case 0:
                    if ('1' == trim(substr($XAUX, $xz * 6, 6))) {
                        $xcadena.= 'UN BILLON ';
                    } else {
                        $xcadena.= ' BILLONES ';
                    }
                    break;
                case 1:
                    if ('1' == trim(substr($XAUX, $xz * 6, 6))) {
                        $xcadena.= 'UN MILLON ';
                    } else {
                        $xcadena.= ' MILLONES ';
                    }
                    break;
                case 2:
                    if (1 > $numero) {
                        $xcadena = "CERO {$moneda}S {$xdecimales}/100 {$subfijo}";
                    }
                    if ($numero >= 1 && $numero < 2) {
                        $xcadena = "UN {$moneda} {$xdecimales}/100 {$subfijo}";
                    }
                    if ($numero >= 2) {
                        $xcadena.= " {$moneda}S {$xdecimales}/100 {$subfijo}"; //
                    }
                    break;
            } // endswitch ($xz)
        } // ENDIF (trim($xaux) != "")

        $xcadena = str_replace('VEINTI ', 'VEINTI', $xcadena); // quito el espacio para el VEINTI, para que quede: VEINTICUATRO, VEINTIUN, VEINTIDOS, etc
        $xcadena = str_replace('  ', ' ', $xcadena); // quito espacios dobles
        $xcadena = str_replace('UN UN', 'UN', $xcadena); // quito la duplicidad
        $xcadena = str_replace('  ', ' ', $xcadena); // quito espacios dobles
        $xcadena = str_replace('BILLON DE MILLONES', 'BILLON DE', $xcadena); // corrigo la leyenda
        $xcadena = str_replace('BILLONES DE MILLONES', 'BILLONES DE', $xcadena); // corrigo la leyenda
        $xcadena = str_replace('DE UN', 'UN', $xcadena); // corrigo la leyenda
    } // ENDFOR ($xz)
    return trim($xcadena);
}

/**
 * Esta función regresa un subfijo para la cifra
 * 
 * @author Ultiminio Ramos Galán <contacto@ultiminioramos.com>
 * @param string $cifras La cifra a medir su longitud
 */
function subfijo($cifras)
{
    $cifras = trim($cifras);
    $strlen = strlen($cifras);
    $_sub = '';
    if (4 <= $strlen && 6 >= $strlen) {
        $_sub = 'MIL';
    }

    return $_sub;
}

/*  EOF  */

Segundo, creamos una vista

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Convertir números a letras con PHP/CodeIgniter 2</title>
        <!--
        La ausencia de http: en el link de abajo NO es un error:
        http://encosia.com/3-reasons-why-you-should-let-google-host-jquery-for-you/#protocolless
        -->
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" ></script>
    </head>
    <body>
        <form name="forma1" action="" method="post">
            <input id="cantidad" type="text" name="cantidad" value="<?php echo isset($_POST['cantidad']) ? $_POST['cantidad'] : ''; ?>" size="50" maxlength="21" /> 
            <input id="boton1" type="button" name="boton1" value="Convertir..." />
            <br/>
            <textarea id="cantidad_letras" cols="100" rows="5"><?php echo isset($_POST['cantidad']) ? numtoletras($_POST['cantidad']) : ''; ?></textarea>
        </form>

        <script type="text/javascript" charset="utf-8">
            /* debes personalizar esta url para apuntar a tu servidor */
            var url_post = 'http://ultiminioramos.com/blog/codeigniter2/index.php/numeros/convertir/';

            jQuery(document).ready(function() {
                $('#cantidad').focus();

                /* Enviar vía ajax la petición */
                $('#boton1').dblclick(function(e) {
                    e.preventDefault();
                });
                $('#boton1').click(function(e) {
                    e.preventDefault();
                    
                    $.ajax({
                        url: url_post
                                , type: 'post'
                                , dataType: 'json'
                                , data: {
                                    cantidad: $('#cantidad').val()
                                }
                                , success: function(response) {
                            $('#cantidad_letras').html(response.leyenda);
                            $('#cantidad').val(response.cantidad);
                        }
                    });
                });
            });
        </script>
    </body>
</html>

Tercero, creamos el controlador

<?php

/**
 * Ejemplo en CodeIgniter 2 para convertir números a letras
 *
 * @author Ultiminio Ramos Galán <contacto@ultiminioramos.com>
 */
class numeros extends CI_Controller
{

    public function __construct()
    {
        parent::__construct();
    }

    public function index()
    {
        $this->load->helper('numeros');

        $this->load->view('v_numeros');
    }

    public function convertir()
    {
        $cantidad = trim($this->input->post('cantidad'));

        if (empty($cantidad)) {
            echo json_encode(array('leyenda' => 'Debe introducir una cantidad.'));
            
            return;
        }
        
        # verificar si el número no tiene caracteres no númericos, con excepción
        # del punto decimal
        $xcantidad = str_replace('.', '', $cantidad);
        
        if (FALSE === ctype_digit($xcantidad)){
            echo json_encode(array('leyenda' => 'La cantidad introducida no es válida.'));
            
            return;
        }

        # procedemos a covertir la cantidad en letras
        $this->load->helper('numeros');
        $response = array(
            'leyenda' => num_to_letras($cantidad)
            , 'cantidad' => $cantidad
            );
        echo json_encode($response);
    }

}
/* EOF */

El código fuente lo puedes descargar desde aquí numeros_a_letras_CI2.zip

Espero que les haya sido de utilidad.

domingo, 14 de abril de 2013

Cómo llamar un "config item" dentro de un helper en CodeIgniter

Este sencillo pero útil "tip" te va a ayudar a llamar un elemento de configuración (config item) desde un helper, una vista, un modelo, o algún otro tipo de archivo php que no sea un controlador (controller). Como sabemos y tal como la documentación de CodeIgniter lo indica, un config item se llama de la siguiente manera:
$xss_conf = $this->config->item('global_xss_filtering');
Pero, si hacemos esto en algún otro archivo php tal como una vista o un helper, recibiremos un error como éste:
Fatal error: Using $this when not in object context in translate_helper.php on line 31
Lo que debes hacer es usar la siguiente sintaxis:
$ci =& get_instance();
$xss_conf = $ci->config->item('global_xss_filtering');
Pero mejor aún, de una manera más sencilla, puedes usar:
$xss_conf = config_item('global_xss_filtering');

Espero que les haya sido de mucha utilidad como a mí.

La referencia a este tip está en: http://ellislab.com/forums/viewthread/130472/#643868

jueves, 7 de junio de 2012

CodeIgniter: Evitar XSS para grabar HTML tags y sus atributos

En algunas ocasiones es necesario grabar datos con código HTML y sus respectivos atributos, esto es recomendable hacerlo sobre todo en aplicaciones de backend, donde se tiene el control de qué usuarios pueden insertar o modificar información.

Esto claramente es un problema de seguridad por la inyección de código malicioso si se establecen estas preferencias en un ambiente de front-end pues ahí sí, un desconocido puede inyectar código malicioso como scripts de Javascript e incluso de php o perl o cgis.

  1. Hay que establecer la variable global_xss_filtering a FALSE, dentro del archivo application/config/config.php
    $config['global_xss_filtering'] = FALSE;
    
  2. Ya sea en el modelo o en un controlador, se deben obtener los datos y filtrarlos con la libreria XSS CLEAN que incorpora CodeIgniter
    $a_input_post = $this->input->post(NULL, TRUE); # retorna todos los elementos POST con el filtro XSS
    
    Ahora puedes trabajar con los campos de manera segura que se han filtrado y puesto en la variable $a_input_post
     
  3. Para grabar los datos de un campo específico en donde queremos tener el html íntegro desde el origen, lo que hay que hacer es evitar filtrar solamente ese campo:
    $this->db->set('descripcion', $this->input->post('mi_campo_html', FALSE));
    

jueves, 22 de julio de 2010

CodeIgniter Integrando NuSoap: Web Services


En este artículo les comparto como integrar la librería NuSoap 0.9.5 dentro de CodeIgniter 1.7.2, crearemos un servidor y luego un cliente. Es importante tener algunos conocimiento previos, para que comprendas que es lo que se está haciendo y posteriormente puedas hacer las modificaciones para adaptar este código a tus necesidades. Aquí algunas ligas que ayudan a esto.

http://www.youtube.com/watch?v=ye3T5bXqdDs
http://www.youtube.com/watch?v=s3igsOCMwcg
http://www.youtube.com/watch?v=TRg9zu9kuHw&feature=related

Datos personales

Mi foto
Podrás encontrar códigos recursos y artículos sobre PHP, JavaScript, jQuery, MooTools, Ajax, CSS, HTML, UML, RUP, AUP, XP (eXtreme Programming), Six-Sigma, CMMI, FrameWorks, Zend Framework, Magento, CodeIgniter, CakePHP, Joomla 1.5, Doctrine, Active Record, ORM, POO, MVC, MySql, PostgreSql. Este espacio está destinado a ayudar y compartir un poco de lo mucho que he recibido de la comunidad en la Red.