Mostrando entradas con la etiqueta php. Mostrar todas las entradas
Mostrando entradas con la etiqueta php. 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.

martes, 18 de junio de 2013

Cómo hacer una prueba de estrés con JMeter

Les presento sencillos pasos para diseñar, ejecutar y obtener los resultados de una prueba de estrés usando JMeter con una aplicación basada en Web construida en PHP (para este ejemplo).

Tenemos que crear un escenario o plan de pruebas, para ello, nos vamos a auxiliar de JMeter, el cual puedes descargar desde el sitio de apache http://jmeter.apache.org/download_jmeter.cgi.

Paso 1: Instalar y ejecutar JMeter

La instalación simplemente es descomprimir el .zip o el .tgz en tu disco duro. Una vez hecho esto, en la carpeta de JMeter hay una carpeta bin, ejecutar el archivo jmeter.bat

Paso 2: Configurar JMeter para el escenario de prueba

Para efectos de este ejemplo, prefiero usar el idioma en inglés, pues la traducción al castellano es literal y a menudo es difícil navegar entre las opciones.

Así que para cambiar el idioma de español a inglés: Menú Opciones >> Elija lenguaje >> Inglés

Seleccionamos el nodo de Test Plan y le ponemos un nombre que nos ayude a identificarlo, luego le damos clic derecho y Add >> Thread Group

Llenamos los campos Name, y en el apartado de Action to be taken after a Sample error

En el apartado de Thread Properties, Number of Threads (users), Ramp-up Period (in seconds), Loop Count __ Forever, como se muestra en la imagen siguiente:

Paso 3: Configurar los valores de la petición HTTP

Sobre el nodo de tu nuevo Thread Group, haz clic derecho y Add >> Config Element >> HTTP Request Defaults

Selecionamos el elemento agregado y configuramos sus parámetros.

El campo Name, le pones un nombre descriptivo o lo puedes dejar así, en este ejemplo, prefiero dejarlo como viene el default

En el apartado Web Server, llenar los campos Server Name or IP:, Port Number, con los datos del servidor que quieras probar, en este ejemplo, el servidor está en una LAN y accedemos al aplicativo que queremos probar mediante el puerto 8084, pero una configuración típica si pruebas en tu localhost es poner 127.0.0.1 y en puerto 8080.

En el apartado HTTP Request, en la lista Implementation, seleccionar HttpClient4, en el campo Protocol [http], no hay más que poner http, en el campo Content encoding poner el que tú manejas en tus páginas web, en mi caso, utilizo UTF-8.

En el campo Path, poner la ruta de la raíz de tu aplicativo, puede ser / o en mi caso, utilizo /ejemplo_jmeter

Paso 4: Configurar el HTTP Proxy Server

En el nodo Workbench, acer clic derecho y Add >> Non-Test Elements >> HTTP Proxy Server

Puedes darle un nombre o dejar el que tiene por default, en mi ejemplo he decidio dejar el default. En el apartado Global Settings, en Port: 8080

En el apartado Test plan content, en la lista Target Controller seleccionar de la lista el plan de pruebas que vamos a generar y este va a ser el repositorio que va a recibir todas las peticiones que se van a "grabar".

En la imagen de abajo verán los demás parámetros, después con más práctica y de acuerdo a la necesidad específica de cada proyecto, pueden modificar los demás parámetros.

Paso 5: Configurar el navegador donde se va a ejecutar la prueba

Es necesario configurar un servidor proxy, pues una vez que se ejecute el escenario de pruebas que dimos de alta en JMeter, éste se convierte en un proxy, por el cual van a pasar todas peticiones HTTP.

Para el ejemplo, asumo que como todo buen programador, usan cualquier navegador que no sea Internet Explorer, así que en la imagen van a ver la configuración proxy para Mozilla Firefox:

Paso 6: Ejecutar el proceso de grabación de nuestro escenario de pruebas

Ahora en la pantalla de HTTP Proxy Server que acabamos de configurar, presionamos el botón Start, para iniciar el servidor proxy.

Ingresamos al navegador al cual tiene configurado que use el proxy, e introducimos la url de nuestro aplicativo que queremos probar.

Navegamos dentro de nuestra aplicación para que comience a "grabar" nuestro escenario de pruebas, el concepto es parecido a grabar una macro.

Una vez que ya recorrimos todo lo que nos interesa "testear", podemos regresar a JMeter y damos Stop al servidor proxy (que se ubica en el nodo Workbench >> HTTP Proxy Server).

Entonces, ahora nuestro escenario de pruebas ya tiene varias ramas, que debe verse más o menos como en la siguiente imagen:

Paso 7: Hay que agregar unos "Listeners" que van a recopilar los resultados de la prueba y nos darán ciertos resultados

Hay algunos que son muy interesantes, pero para esta primera prueba, te recomiendo agregar el listener View Results in Table, entonces haz clic derecho en el Thread Group, que en este ejemplo le pusimos por nombre "Proceso de login", Add >> Listener y finalmente View Results in Table.

Se pueden agregar varios listeners a la vez. Todo depende de qué tipo de resultados deseas obtener y cómo quieres que sean presentados.

Paso 8: Ejecutar el escenario de pruebas ¡por fin!

Ahora sí, seleccionas el nodo Thread Group (el cual le pusimos por nombre "Proceso de login" y presionamos Ctrl + R, ó menú Run >> Start ó podemos hacer clic en el botón verde de start (el típico ícono de play).

¡A disfrutar!

Tip extra:

Voy a ponerte un posible escenario: en mi ejemplo, vamos a ejecutar una prueba de estrés usando un usuario para hacer el login, pero como hay una regla de negocio que indica que no pueden haber un mismo usuario conectado más de 1 vez simultáneamente, la solución es introducir diferentes usuarios para ejecutar todas las conexiones concurrentes para la prueba de estrés.

Para lograr esto, lo que tenemos que hacer es agregar parámetros de usuario los cuales podemos ingresar haciendo clic derecho en el nodo Thread Group, que en este ejemplo le pusimos por nombre "Proceso de login", Add >> Pre Processors >> User Parameters.

Con el botón Add Variable agregamos las dos variables que necesitamos para username y password.

Con el botón Add User agregamos varios usuarios con su password de nuestro aplicativo, en mi ejemplo introduje 100 usuarios de mi base de datos, ver imagen de abajo:

Luego, debes ubicar en el árbol de requests el recurso que envía los datos de usuario y contraseña, en mi ejemplo, lo señalo en la imagen de abajo, y verás como llenar los campos para inyectar los diferentes valores usando unas variables, típicamente se colocan con el siguiente formato: ${variable}

Finalmente, volver a ejecutar como lo dijimos en el paso 8.

Bueno, espero haber que este post les sea de utilidad, creo que todo programador aunque no sea tester, debe hacer pruebas de rendimiento, la prueba de estrés es solamente una de ellas.

jueves, 30 de mayo de 2013

Como convertir un archivo o string XML en un array en PHP 5, usando SimpleXML

La solución es muy sencilla, para este ejemplo, utilizaremos la librería SimpleXML. Esta libería requiere la extensión de PHP libxml y funciona a partir de PHP 5.

Voy a usar el xml de ejemplo que viene en la documentación de PHP.
# aquí debes poner la ruta y el nombre de tu archivo xml
$xmlstring = realpath(dirname(__FILE__)) . '/xmls/prueba.xml';

if (!file_exists($xmlstring)) {
   trigger_error(__FILE__: {$xmlstring}", E_USER_ERROR);
   return;
}

$xml = simplexml_load_file($xmlstring);
        
$json = json_encode($xml);
$array = json_decode($json, TRUE);
echo '<pre>';
print_r($xml);
echo '</pre>';

echo '<pre>';
print_r($array);
echo '</pre>';
Nota: el inconveniente de pasar el objeto XML a un array con esta técnica, es que se pierden los atributos de los elementos, como en el caso de los atributos del elemento <puntuacion>, que se pierden los atributos "tipo", pero seguramente para determinados casos esta sencilla técnica puede servir muy bien.

El resultado de este ejemplo para el objeto simpleXML sería:

SimpleXMLElement Object
(
    [pelicula] => SimpleXMLElement Object
        (
            [titulo] => PHP: Tras el Parser
            [personajes] => SimpleXMLElement Object
                (
                    [personaje] => Array
                        (
                            [0] => SimpleXMLElement Object
                                (
                                    [nombre] => Srta. Programadora
                                    [actor] => Onlivia Actora
                                )

                            [1] => SimpleXMLElement Object
                                (
                                    [nombre] => Sr. Programador
                                    [actor] => El Actor
                                )

                        )

                )

            [argumento] => 
            Así que, este lenguaje. Es como, un lenguaje de programación. ¿O es un
            lenguaje interpretado? Lo descubrirás en esta intrigante y temible parodia
            de un documental.
        
            [grandes-lineas] => SimpleXMLElement Object
                (
                    [linea] => PHP soluciona todos los problemas web
                )

            [puntuacion] => Array
                (
                    [0] => 7
                    [1] => 5
                )

        )

)

El resultado de este ejemplo para el array sería:

Array
(
    [pelicula] => Array
        (
            [titulo] => PHP: Tras el Parser
            [personajes] => Array
                (
                    [personaje] => Array
                        (
                            [0] => Array
                                (
                                    [nombre] => Srta. Programadora
                                    [actor] => Onlivia Actora
                                )

                            [1] => Array
                                (
                                    [nombre] => Sr. Programador
                                    [actor] => El Actor
                                )

                        )

                )

            [argumento] => 
            Así que, este lenguaje. Es como, un lenguaje de programación. ¿O es un
            lenguaje interpretado? Lo descubrirás en esta intrigante y temible parodia
            de un documental.
        
            [grandes-lineas] => Array
                (
                    [linea] => PHP soluciona todos los problemas web
                )

            [puntuacion] => Array
                (
                    [0] => 7
                    [1] => 5
                )

        )

)

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 usando PHP 5 / Poo y aplicando MVC

Es la misma función que hice para convertir números a letras (tanto scriptera como la versión para CodeIgniter), pero ahora hecha con programación orientada a objetos

Como un valor adicional, vamos a aplicar el patrón de diseño MVC (modelo, vista, controlador)

Para este ejemplo voy a suponer que ya conoces las bases de POO (programación orientada a objetos), de lo contrario sugiero primero buscar documentación en la web

Puedes ejecutar el demo desde aquí Convertir números a letras PHP 5 Poo/MVC

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

Primero, debemos crear una estructura de archivos que contenga:

  • un archivo index.php
  • una carpeta controller
    • un archivo c_numeros.php
  • una carpeta model
    • un archivo m_numeros.php
  • una carpeta view
    • un archivo v_numeros.php

Segundo, editamos el archivo ruteador index.php y colocamos este código:

<?php

/**
 * Ruteador para aplicar el modelo MVC simple
 * 
 * @author Ultiminio Ramos Galán <contacto@ultiminioramos.com>
 * @date 2013-05-16
 */

# cargar el controlador
include 'controller/c_numeros.php';

$instancia = new C_numeros();

$instancia->index();

/* EOF */

Tercero, editamos el archivo del controlador c_numeros.php y colocamos este código:

<?php
/**
 * Clase controladora
 * 
 * @author Ultiminio Ramos Galán <contacto@ultiminioramos.com>
 * @date 2013-05-16
 */

class C_numeros
{

    protected $_letras = '';
    protected $_cantidad;

    public function __construct()
    {
        
    }

    public function index()
    {
        if (isset($_POST['cantidad'])) {
            # preparar la variable
            $this->_prepararDatos();

            # cargar el modelo
            $modeloNum = $this->_cargarModelo('m_numeros');

            # ejecutar la conversion a letras
            try {
                $this->_letras = $modeloNum->numeroLetras($this->_cantidad);
            } catch (Exception $e) {
                $letras = 'Ocurrió un error.';
            }
        }

        # cargar la vista
        $view_data['cantidad'] = $this->_cantidad;
        $view_data['letras'] = $this->_letras;

        $this->_cargarVista('v_numeros', $view_data);
    }

    /**
     * En este método puedes validar el dato de entrada y 
     * agregar funcionalidad adicional
     * 
     * @return void
     */
    protected function _prepararDatos()
    {
        $this->_cantidad = trim($_POST['cantidad']);

        return;
    }

    /**
     * Instancia la clase del modelo y regresa el objeto
     * 
     * @param string $modelo
     * @return object
     */
    protected function _cargarModelo($modelo)
    {
        include "model/{$modelo}.php";
        
        return new M_numeros();
    }

    /**
     * Cargar la vista
     * 
     * @param string $vista
     * @param array $datos_vista
     */
    protected function _cargarVista($vista, $datos_vista)
    {
        include "view/{$vista}.php";
    }

}

Cuarto, editamos el archivo de la vista v_numeros.php y colocamos este código:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Convertir números a letras con PHP 5/Poo </title>
    </head>
    <body>
        <form name="forma1" action="" method="post">
            <div style="width: 100%; display: block;">
                <input id="cantidad" type="text" name="cantidad" value="<?php echo $datos_vista['cantidad']; ?>" size="50" maxlength="21" /> 
                <input id="boton1" type="submit" name="boton1" value="Convertir..." />
            </div>
            <div style="width: 100%; display: block;">
                <textarea id="cantidad_letras" cols="100" rows="5"><?php echo $datos_vista['letras']; ?></textarea>
            </div>
        </form>

        <script type="text/javascript" charset="utf-8">
        </script>
    </body>
</html>

Quinto, editamos el archivo del modelo m_numeros.php y colocamos este código:

<?php
/**
 * Clase del proceso de negocio (modelo)
 * 
 * @author Ultiminio Ramos Galán <contacto@ultiminioramos.com>
 * @date 2013-05-16
 */

class M_numeros
{

    /**
     * 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
     */
    public function numeroLetras($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 = $this->_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 = $this->_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 = $this->_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
     */
    private function _subfijo($cifras)
    {
        $cifras = trim($cifras);
        $strlen = strlen($cifras);
        $_sub = '';
        if (4 <= $strlen && 6 >= $strlen) {
            $_sub = 'MIL';
        }

        return $_sub;
    }

}

/*  EOF  */

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

Espero que les haya sido de utilidad.

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

viernes, 29 de marzo de 2013

Cómo implementar el patrón de diseño Singleton en PHP

El patrón de diseño Singleton es creado para asegurarse de tener solamente una instancia de un objeto durante la ejecución de un hilo en un proceso determinado. Un ejemplo típico de esto es tener una instancia del objeto de conexión a la base de datos. Para mayores referencias sobre este patrón de diseño, pueden ir a la wikipedia.

Bien, me voy a enfocar a explicar cómo implementarlo en php, el cual con esta ténica es soportada a partir de php 5.0+ pues en versiones anteriores el manejo de ciertos métodos mágicos no funcionaría.


<?php

/**
 * Description of Singleton
 *
 * @author Ultiminio Ramos
 */
class Singleton
{

    private static $instancia;
    private $_contador;

    /**
     * Declaramos private el método constructor, para evitar acceder a él cada vez
     * que se realiza la instanciación de esta clase
     */
    private function __construct()
    {
        echo 'Se ha instanciado una clase (<code style="color: blue; font-weight: bolder;">' . __CLASS__ . "</code>)< br/>";

        $this->_contador = 0;
    }

    /**
     * Punto global de acceso a la clase, pues el método constructor lo hemos
     * declarado como private para asegurarnos de que no se puede acceder a él
     * sino solamente por medio de este método llamado getInstance()
     * 
     * @return object
     */
    public static function getInstance()
    {
        if (!self::$instancia instanceof self) {
            self::$instancia = new self;
        }

        return self::$instancia;
    }

    /**
     * Método público que ya es accesible desde un objeto instanciado
     */
    public function incrementar()
    {
        return ++$this->_contador;
    }

    /**
     * Método público que ya es accesible desde un objeto instanciado
     */
    public function disminuir()
    {
        return --$this->_contador;
    }

    /**
     * Método mágico que nos permite gestionar la clonación y evitar que se rompa
     * el patrón singleton
     */
    public function __clone()
    {
        $error_msg = 'No se permite la clonación dentro del patrón singleton';
        $error_msg.= '(<code style="color: blue;">' . get_class($this) . '</code>)';

        //trigger_error($error_msg, E_USER_NOTICE); # mandamos un mensaje, pero la ejecución no se interrumpe
        trigger_error($error_msg, E_USER_ERROR); # interrumpimos la ejecución
    }

    /**
     * Método mágico para gestionar la serialización y por consiguiente 
     * evitar romper el patrón singleton
     */
    public function __wakeup()
    {
        $error_msg = 'No se permite la serialización dentro del patrón singleton';
        $error_msg.= '(<code style="color: blue;">' . get_class($this) . '</code>)';

        trigger_error($error_msg, E_USER_ERROR); # interrumpimos la ejecución
    }

}

Ahora, es momento de probar nuestro patrón de diseño.

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Probar el patrón Singleton en PHP 5.0+</title>
    </head>
    <body>
        <?php
        include_once 'app/test_singleton/model/Singleton.php';

        $br = '< br/>'; 

        $instancia = Singleton::getInstance();
        echo '<pre>';
        echo 'instancia(++$i) = ' . $instancia->incrementar() . $br;
        echo 'instancia(++$i) = ' . $instancia->incrementar() . $br;
        echo 'instancia(++$i) = ' . $instancia->incrementar() . $br;
        echo 'instancia(++$i) = ' . $instancia->incrementar() . $br;
        echo 'instancia(++$i) = ' . ($instancia->incrementar()) . $br;
        echo '<hr/>';

        # probar la clonación como técnica para romper el patrón singleton
        $clone = clone($instancia);

        echo 'clone_instancia(--$i) = ' . $clone->disminuir() . $br;
        echo 'clone_instancia(--$i) = ' . $clone->disminuir() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
   
        # probar la serialización/deserialización como técnica para romper el patrón singleton
        $serializado = serialize($instancia);
        $unserializa = unserialize($serializado);
        echo '$unserializa(++$i) = ' . $unserializa->incrementar() . $br;
        echo '$unserializa(++$i) = ' . $unserializa->incrementar() . $br;
        echo '$unserializa(++$i) = ' . $unserializa->incrementar() . $br;
        echo '$unserializa(++$i) = ' . $unserializa->incrementar() . $br;

        # comprobación
        echo '.' . $br;
        echo '.' . $br;
        echo '.' . $br;

        echo 'instancia(++$i) = ' . $instancia->incrementar() . $br;

        echo '</pre>';
        ?>
    </body>
</html>

Espero les sirva el ejemplo, y como dijeran los gringos: "happy conding"

miércoles, 20 de febrero de 2013

Validar email con expresiones regulares en PHP

Hay en la web diferentes expresiones regulares que validan direcciones de correo electrónico, pero tienen huecos, así que les paso una muy buena y robusta, que encontré en un software que se llama Expresso (http://www.ultrapico.com) y se las comparto a ustedes. La aplico en PHP pero como saben pueden usarla en Javascript y cualquier otro lenguaje.


Débiles expresiones regulares que encontré en la web, que permiten pasar direcciones como: uramos@gmail, uramos@gmail., uramos@gmail.com.
preg_match("^([a-z0-9_-])+([\.a-z0-9_-])*@([a-z0-9-])+(\.[a-z0-9-]+)*\.([a-z]{2,6})$", $email);
preg_match("/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/", $email);


Verdadera expresión regular que valida direcciones de correo:
function validarEmailAddress($email)
{
   // Regresa 1 si la cadena hace match
   // Regresa 0 si no hace match
   // Regresa FALSE si hubo un error
   return preg_match("/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})+$/", $email);
}

Las funciones de PHP ereg() y eregi() son obsoletas y quedarán fuera desde la versión 5.3, por eso usamos preg_match()

jueves, 14 de febrero de 2013

Magento: WSDL, limpiar los archivos del caché de PHP

Problema: Durante el desarrollo y exposición de Web services desde Magento usando SOAP, he tenido que prender y apagar el setting de "Enable WSDL Cache", y a veces, no actualiza los cambios realizados a las estructuras de datos definidos en los archivos wsdl.xml.

Solución: Eliminar los archivos temporales que PHP genera para el manejo de caché del archivo WSDL, así que:

Acceder a la carpeta temporal de tu servidor (linux), y eliminar los archivos temporales de wsdl:

cd /tmp
ls wsdl-* -l
rm wsdl-*

Listo, eso es todo.

Como beneficio adicional, seguramente esta acción evitará falsos errores de SOAP como:
  • Invalid API path
  • Is not a valid method
  • Resource path not callable

miércoles, 13 de febrero de 2013

Magento: SOAP V2, mejorar el tiempo de respuesta

Hay muchas razones por las que una petición a un web service usando SOAP V2 puede tomar mucho tiempo, pero la primera cosa que pienso es revisar la configuración para activar la caché en la construcción del archivo WSDL. Cuando se hace una llamada a la API de Magento, Magento usa el objecto SoapServer de PHP. El objeto SoapServer necesita obtener su propio archivo WSDL para poder funcionar, y la generación y extracción de este archivo puede consumir mucho tiempo.

La solución para esto es habilitar el manejo de caché para el archivo WSDL, que por defecto viene apagado en Magento. 


Acceder al backend de Magento, luego a System->Configuration->Magento Core API
Busca el rubro "Enabled WSDL Cache" y cámbialo a Yes.



Haciendo esto, mejorarás notablemente el tiempo de respuesta de las llamadas a la API, aclaro que esto funciona a partir de la versión 1.6 de Magento usando SOAP V2, para versiones anteriores hay una solución en este link: http://www.ivoronline.com/Coding/Languages/PHP/Tutorials/PHP - API - SOAP - Extension - Introduction.php

Este parámetro no existe en versiones anteriores a 1.6 de Magento, pero también existe una extensión comercial hecha por Alan Storm, y se llama "Mercury API Extension". Aunque también se puede mirar la clase Mage_Api_Model_Server_Adapter_Soap donde las versiones anteriores de Magento deshabilitan esta caché.

Esta solución fue tomada de Alan Storm desde Stackoverflow.com

martes, 28 de agosto de 2012

Magento: Cómo crear/usar variables globales

A partir de Magento 1.4 se pueden usar las variables personalizadas, o si lo quieres ver de otra manera "constantes" que pueden ser usadas a lo largo de tu código en Magento.

En este caso, voy a ejemplificarlo con el uso de una variable que me es muy útil para controlar el uso de la directiva display_errors de php.ini para los entornos de desarrollo/producción

Paso 1:

Acceder al backend de Magento, luego a System->Custom Variables

Paso 2:
Agregar una nueva variable. En el formulario ingresar los datos:
  • Variable Code. Aquí va el nombre de la variable, lo recomendable es nombrar una variable de acuerdo a la sintaxis de php (pero sin el signo de $)
  • Variable Name. Aquí se debe poner la descripción de la variable
  • Variable HTML Value. Opcional, se puede usar este campo que permite tags de HTML o usar el campo de abajo o ambos, y decidir en tu programación cual de los dos valores quieres que te retorne: el valor HTML o el valor de texto plano
  • Variable Plain Value. Colocar el valor que se desea, pero aquí no se acepta código HTML
Guardar los datos. Ahora vayamos al código para saber cómo usar esta nueva variable.

Paso 3:
Usar el siguiente código:

// por default, el tipo de datos es un string
$objVar = Mage::getModel('core/variable')->loadByCode('display_errors');
$display_errors = $objVar->getValue('plain');
ini_set('display_errors', $display_errors);

// pero puedes explícitamente cambiar el tipo:
$display_errors = (int) $objVar->getValue('plain');
ini_set('display_errors', $display_errors);

// booleano:
$display_errors = (boolean) $objVar->getValue('plain');
ini_set('display_errors', $display_errors);

// de punto flotante:
$display_errors = (double) $objVar->getValue('plain');
ini_set('display_errors', $display_errors);
Para este ejemplo, todos los tipos de datos son válidos para la directiva ini_set('display_errors', string|int|bool|double)

Y como te imaginarás, en el método getValue() puedes poner 'html' en lugar de 'plain'

Espero que te sea de utilidad y como dicen los gringos: Happy coding!

lunes, 13 de agosto de 2012

Magento: Cómo reducir el tamaño de los archivos PDF

Para reducir el tamaño de los archivos PDF que genera Magento, tales como las facturas (invoices), pedidos (orders), etc. se necesita usar una fuente (fonts) diferentes a las predeterminadas.

Los archivos PDF generados por Magento tienen un tamaño alrededor de 1.5 MB, esto se debe a que la fuente predeterminada es /lib/LinLibertineFont/LinLibertineC_Re-2.8.0.ttf

La cual por sí misma pesa 1.5 MB. La solución es reemplazar esta fuente por alguna estándar de Zend_Pdf, para hacer esto, solamente abre el archivo app/code/core/Mage/Sales/Model/Order/Pdf/Abstract.php

Busca la siguiente línea:

$font = Zend_Pdf_Font::fontWithPath(Mage::getBaseDir() . '/lib/LinLibertineFont/LinLibertineC_Re-2.8.0.ttf');
#
#

Y reemplázala con:

$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA);
#
#

Esto reducirá hasta en un 90% el tamaño de los archivos PDF generados en Magento

Si deseas aumentar el tamaño de las fuentes para las facturas, direcciones de envío, etc., puedes cambiar las líneas:

protected function _setFontRegular($object, $size = 7)
protected function _setFontBold($object, $size = 7)
protected function _setFontItalic($object, $size = 7)

Por:

protected function _setFontRegular($object, $size = 9)
protected function _setFontBold($object, $size = 9)
protected function _setFontItalic($object, $size = 9)

Como podrás ver, hemos tocado el core de Magento, para preservar las modificaciones para futuras actualizaciones de Magento, puedes colocar este código en app/local/Mage/Sales/Model/Order/Pdf/Abstract.php, pero toma en cuenta que con el simple hecho de colocarlo en esta carpeta no quiere decir que vas a sobreescribir la clase, sino que simplemente es a manera de "backup" para que sepas que ahí puedes recolectar los cambios hechos al core de Magento cuando hagas una actualización de versión y repetir estos pasos para un futuro.

Ahora bien, si no quieres tocar el core de Magento, puedes extender la clase app/code/core/Mage/Sales/Model/Order/Pdf/Abstract.php y entonces sobreescribir los métodos arriba mencionados. Por el momento no voy a tocar el tema de cómo extender módulos en Magento, pero te dejo unos links en inglés que te pueden servir:

http://blog.chapagain.com.np/magento-block-controller-model-helper-override/

http://blog.theunical.com/ecommerce/shopping-carts/magento-cart/magento-how-to-create-a-custom-plugin-module-example-tutorial/

http://www.webspeaks.in/2010/07/create-your-first-magento-module.html

 

Artículo original:
http://www.magpleasure.com/blog/change-fonts-and-reduce-file-size-for-pdf-invoice-in-magento.html

martes, 24 de julio de 2012

Magento: Cómo crear un helper

La creación de un helper en Magento es muy simple, lo que sí es muy importante, es tener cuidado en el uso de las mayúsculas y minúsculas, así como en el uso de comentarios en los archivos xml.

Este artículo también pretende ser un breve tutorial para comprender el porqué de las cosas.

1) Hay que crear un módulo para alojar nuestro helper, para ello, necesitamos crear un nuevo archivo en la carpeta app/etc/modules/ el cual llamaremos Micodigo.xml

Poner el siguiente código dentro:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Micodigo_Mihelper>
            <codePool>local</codePool>
            <active>true</active>
        </Micodigo_Mihelper>
    </modules>
</config>

Micodigo representa un espacio de nombres (Namespace) en donde podemos colocar uno o varios módulos nuestros.

Mihelper representa el nombre de nuestro módulo

En el nodo codePool, local significa que nuestro módulo es exclusivamente para nuestra necesidad específica (en Magento, community es por lo general para los plug-ins libres o comerciales que la comunidad de Magento desarrolla y resuelven problemas más comunes, y core significaría que este módulo es de la plataforma de Magento)

2) Crear el directorio app/code/local/Micodigo/Mihelper/etc/ y crear el archivo config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Micodigo_Mihelper>
            <version>1.0.0</version>
        </Micodigo_Mihelper>
    </modules>
    
    <global>
        <helpers>
            <mihelper>
                <class>Micodigo_Mihelper_Helper</class>
            </mihelper>
        </helpers>
    </global>
</config>

3) Crear la carpeta app/code/local/Micodigo/Mihelper/Helper/ y crear el archivo Data.php

<?php
class Micodigo_Mihelper_Helper_Data extends Mage_Core_Helper_Abstract
{

    public function test()
    {
        return 'Hola mundo' ."\n";
    }

}

4) Usar el helper de la siguientes maneras:

echo Mage::helper('mihelper')->test();
$helper = Mage::helper('mihelper')
echo $helper->test();

O si lo prefieres, puedes probarlo desde el shell, ya sea que hayas iniciado una sesión por SSH en linux:

1) Crear un archivo test.php en la carpeta raíz de Magento, y poner este código:

<?php
require 'app/Mage.php';
Mage::App('default');
if (!Mage::isInstalled()) {
    echo "Application is not installed yet, please complete install wizard first.";
    exit;
}

$_SERVER['SCRIPT_NAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_NAME']);
$_SERVER['SCRIPT_FILENAME'] = str_replace(basename(__FILE__), 'index.php', $_SERVER['SCRIPT_FILENAME']);
ini_set('display_errors', '1');

require 'Mage/Core/Helper/Data.php';
echo Mage::helper('mihelper')->test();

2) Ejecutarlo desde el prompt de linux, con un comando como este (hay que tomar en cuenta que la ubicación del archivo php binario varía según la distribucion de linux que estés usando, en este caso es con CentOS 6):

/usr/bin/php ./test.php

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

viernes, 25 de mayo de 2012

CentOS 5 - Actualización de PHP 5.1 a 5.2 o a 5.3, en un servidor 1and1

CentOS 5 - Actualización de PHP 5.1 a 5.2 o a 5.3, en un servidor 1and1

En paquetes de Virtual Server o Dedicated Server de 1and1.

Es necesario actualizar PHP 5.1 a 5.2 (o 5.3) en CentOs 5 porque PHP 5.1 no tiene soporte para JSON, entonces:

  1. Desde una sesión de ssh console, crear un archivo de repositorio (ver Webografía al final):
             cd /etc/yum.repos.d
             vi atomic.repo 
          

jueves, 5 de abril de 2012

Configurar Joomla y SMTP con servidores 1and1 y 000webhost

Cómo configurar SMTP para Joomla 1.5 y 2.5 para que están alojados en servidores 1and1 y 000webhost


Para la versión 1.5 de Joomla con 000webhost:

1. Acceder al backend de Joomla, algo así como http://tusitio.com/administrator
2. Ingresa con tus credenciales
3. En el menú Sitio, selecciona Configuración Global


4. En la siguiente pantalla selecciona la pestaña Servidor

5. En el bloque de Configuración de Correo, llena los siguientes campos así:

miércoles, 30 de marzo de 2011

Como quitar con PHP acentos y caracteres raros a una cadena de texto

Como quitar con PHP acentos y caracteres raros a una cadena de texto

He aquí una sencilla forma para reemplazar acentos, tildes, y demás caracteres raros o especiales en una cadena de texto:

$cadenaConAcentos = 'Ésta es una cadena con eñes y áéÍöÜ, Barça,etc.';
$a_tofind = array('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'à', 'á', 'â', 'ã', 'ä', 'å'
   , 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø'
   , 'È', 'É', 'Ê', 'Ë', 'è', 'é', 'ê', 'ë', 'Ç', 'ç'
   , 'Ì', 'Í', 'Î', 'Ï', 'ì', 'í', 'î', 'ï'
   , 'Ù', 'Ú', 'Û', 'Ü', 'ù', 'ú', 'û', 'ü', 'ÿ', 'Ñ', 'ñ');
$a_replac = array('A', 'A', 'A', 'A', 'A', 'A', 'a', 'a', 'a', 'a', 'a', 'a'
   , 'O', 'O', 'O', 'O', 'O', 'O', 'o', 'o', 'o', 'o', 'o', 'o'
   , 'E', 'E', 'E', 'E', 'e', 'e', 'e', 'e', 'C', 'c'
   , 'I', 'I', 'I', 'I', 'i', 'i', 'i', 'i'
   , 'U', 'U', 'U', 'U', 'u', 'u', 'u', 'u', 'y', 'N', 'n');
$cadenaSinAcentos = str_replace($a_tofind, $a_replac, $cadenaConAcentos);
echo $cadenaSinAcentos;

Nota:
Desde la versión de PHP 4.0.5, todos los parámetros de la función str_replace() pueden ser de tipo array.

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.