Te encuentras en la páginas de Blogsperu, los resultados son los ultimos contenidos del blog. Este es un archivo temporal y puede no representar el contenido actual del mismo.
El core (contenido de la carpeta system) es el grupo de archivos más importante de
CodeIgniter, es lo primero que se ejecuta, es el corazón del framework, toda su importancia radica allí y por seguridad es recomendable apartarlo de la carpeta del servidor, sea (
www,
htdocs, etc.), ya que esos directorios albergan los recursos que son accedidos desde fuera de nuestro server (internet, intranet, etc.).
De este modo, si nuestro sitio es atacado, el core del framework no será vulnerable, lo que nos dará un punto más en lo que a seguridad se trata.
nota
Para el ejemplo nuestro directorio de servidor es
/var/www, estamos bajo ambiente
GNU/linux y usamos la versión
2.1.3 de CodreIgniter.
Recuerda siempre respaldar tus proyectos antes de hacer algún cambio.
1.-
descargarmos CodeIgniter, lo descomprimimos en
www, luego lo renombramos (yo le coloqué
proyecto):
2.- luego, movemos (cortamos para luego pegar) la carpeta
system (está dentro de
proyecto) a el nuevo directorio (cualquiera fuera del servidor), en mi caso, la situare en
/opt; Entonces, tengo mi carpeta de CI (proyecto) en www y el core en opt.
El core en /opt:/
... opt
...... system
El resto del proyecto: /var/www/proyecto/
... var
...... www
......... proyecto
............ index.php
............ application
3.- lo siguiente es entrar al
index.php de CI, sabemos que todo lo que se carga en el framework debe pasar por el index (incluso,
si ocultamos el index.php de la url a través del htaccess), ese archivo es el encargado de cargar el core, así que, debemos indicarle donde debe buscarlo.
una vez abierto el index.php, buscamos la variable
$system_path, en mi caso se encuentra en la línea 59.
$system_path = 'system';
cambiamos su valor por la ruta nueva donde colocamos el core, yo lo movi a opt y así queda:
$system_path = '/opt/system';
podriamos incluso, meterlo dentro de otra carpeta o renombrar el directorio system, (ci_core) por ejemplo y quedaría así:
$system_path = '/opt/ci_core';
4.- solo resta guardar los cambios hechos al index.php y probar, no debería haber mayor problema, es importante revisar los permisos del directorio del core una vez que lo movemos.
Si al correr el proyecto, te aparece el mensaje de error:
Your system folder path does not appear to be set correctly. Please open the following file and correct this: index.php es porque tienes mal seteada la ruta nueva donde se encuentra el core.
Si tienes algún problema, no dudes en comentar.

Normalmente no escribo sobre estos temas, pero.. si necesitas formatear con el formato FAT32 desde el seven, una alternativa es usar el software
FAT32 Format, que para los que usamos la PS3, poder seleccionar este formato a la hora de formatear un disco duro externo, es esencial.
Descarga:
http://www.ridgecrop.demon.co.uk/download/fat32format.zip

Sencilla función para generar cadena de colores hexadecimal:
function rnd_color(){
$arr = array('A','B','C','D','E','F');
$cadena = '#';
for($i=0; $i<=5; $i++) $cadena .= $arr[rand(0,5)];
return $cadena;
}ejemplo:
<?php
function rnd_color(){
$arr = array('A','B','C','D','E','F');
$cadena = '#';
for($i=0;$i<=5;$i++) $cadena .= $arr[rand(0,5)];
return $cadena;
}
?>
<html>
<head>
<xstyle>
#mi_div{
background-color:<?php echo rnd_color(); ?>;
margin:0 auto;
width:400px;
height:200px;
border:#000 2px solid;
}
</xstyle>
</head>
<body>
<div id="mi_div"></div>
</body>
</html>


.ui-progressbar .ui-progressbar-value{
background-image: url('http://jqueryui.com/resources/demos/progressbar/images/pbar-ani.gif');
}
.ui-progressbar{
height: 20px;
margin-bottom: 2px;
}
#porcentaje{
margin: 0 auto;
font-size: 12px;
}
#contenedorx{
text-align: center;
width: 99%;
margin-top: -70px;
}
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>ProgressBarUI demo</title>
<link rel="xstylesheet" href="http://code.jquery.com/ui/1.9.1/themes/ui-lightness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.8.2.js"></script>
<script src="http://code.jquery.com/ui/1.9.1/jquery-ui.js"></script>
<xstyle>
.ui-progressbar .ui-progressbar-value{
background-image: url('http://jqueryui.com/resources/demos/progressbar/images/pbar-ani.gif');
}
.ui-progressbar{
height: 20px;
margin-bottom: 2px;
}
#porcentaje{
margin: 0 auto;
font-size: 12px;
}
#contenedor{
margin: 0 auto;
text-align: center;
float: left;
width: 99%;
}
</xstyle>
</head>
<body>
<div id="contenedor">
<div id="progressbar"></div><div id="porcentaje"></div>
</div>
<script>
$("#progressbar").progressbar({value: 0});
function progressBar(){
var value = $("#progressbar").progressbar( "option", "value" );
$('#porcentaje').html((value + 1) + '%');
$("#progressbar").progressbar("option","value",(value+1));
if(value == 99){
clearInterval(continua);
$('#porcentaje').html('-- completo!!');
$("#progressbar").progressbar("option",'value',0);
return;
}
}
continua = setInterval("progressBar()",50);
</script>
</body>
</html>

SelectNav.js es uno de estos plugin interesantes de JQuery, pertenece a la categoróa Responsive Web Design. Convierte listas (UL) usadas para menú de navegación, en elementos select de manera automática, lo que te permite ahorrar espacio en tu diseño, actua dependiendo de la resolución de tu pantalla y es ideal para mostraer contenido en dispositivos móviles.
Para verlo en acción sólo hay que cambiar el tamaño de la página y observar la barra superior.
Compatible con: IE 6 +, Firefox 3.6 +, Chrome 4 +, Safari 3 +, Safari Mobile iOS 3.2 +, Android 2.3 + Navegador, Opera Mobile, Opera Mini.
Descarga:
https://github.com/lukaszfiszer/selectnav.jsUso:
- en
<body></body>:
<ul id="nav">
<li><a href="homepage.html">Homepage</a></li>
<li><a href="about.html" xclass="active">About us</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
en
<head></head>:
<script type="text/javascript" src="Ruta_hacia_el_scripts/selectnav/selectnav.min.js"></script>
<script type="text/javascript">
selectnav('sdt_menu', {
activexclass: 'act',/* clase q indica el elemento activo del menu*/
label: '--- Menú de navegación ---', /* etiqueta - false si no se quiere*/
nested: true, /* activa la navegacion sub-nivel/sub-menus*/
indent: '-' /* separador de sub-menus */
});
</script>

Para evitar inyecciones
XSS,
CodeIgniter(CI) dispone de varios mecanismos para defenderse de estos tipos de ataque. Comenzando con
la clase input, que entre sus funciones, provee métodos auxiliares que re-procesan los datos antes de hacer uso de ellos.
Una de las alternativas nos permite habilitar el filtro XSS que por defecto viene deshabilitado, para ello nos vamos a
application/config/config.php, y buscamos la línea:
$config['global_xss_filtering'] = FALSE;
y la cambiamos por:
$config['global_xss_filtering'] = TRUE;
De esa manera se aplicaría el filtro XSS a todo lo que pase por
POST/
COOKIE.
Si no se desea usar el filtro global, podemos ir filtrando los datos cada vez que los vayamos a usar (pasando TRUE como segundo parámetro):
$this->input->post('mi_campo', TRUE);- Todo lo que viene de la base de datos, también debería ser filtrado antes de imprimirlo en pantalla, CI nos facilita una sencilla función para convertir caracteres HTML a sus entidades correspondientes, haciendo uso de
htmlspecialchars y permitiendonos filtrar un array entero con un sólo llamado:
/**
* Returns HTML escaped variable
*
* @access public
* @param mixed
* @return mixed
*/
if ( ! function_exists('html_escape'))
{
function html_escape($var)
{
if (is_array($var))
{
return array_map('html_escape', $var);
}
else
{
return htmlspecialchars($var, ENT_QUOTES, config_item('charset'));
}
}
}
html_escape esta disponible para ser usada en cualquier momento.
ejemplo de uso:
$var = '<script>alert(1)</script>';
echo html_escape($var).' - ';
$var = array('<script>alert(1)</script>','<b>hola</b>');
print_r(html_escape($var));
otro ejemplo:
function get_data(){
$this->db->query('SELECT mi_campo FROM mi_tabla LIMIT 1');
if ($query->num_rows()>0) {
$row = $query->row_array();
return html_escape($row['mi_campo']);
}else{
return false;
}
}

El presente post es una recopilación sobre la administración básica de base de datos con
PostgreSQL, aclaro que no soy un experto en la materia, mi intención es que el siguiente material pueda servir a quienes se inician en el tema.
Algunos enlaces oficiales:http://www.postgresql.org -> sitio oficial
http://www.enterprisedb.com -> soporte comercial
http://pgmag.org -> revista
http://www.postgresql.org.es -> comunidad española
nota
las pruebas del post están testeadas sobre
Ubuntu (GNU/Linux).
La descargalas descargas la hacemos desde el
apartado download de postgresql.org.
Seleccionas tu plataforma, la arquitectura(32/64bits) y descargas..
También puedes ir directo a
enterprisedb.com para descargar el instalador:
-
http://www.enterprisedb.com/downloads/postgres-postgresql-downloadsLa instalación (para el ejemplo nos bajamos el instalador
postgresql-9.1.4-1-linux-x64.run de
enterprisedb.com).
1.- primero verificamos si esta instalado,
* echando un vistazo a los procesos:
ps auxww | grep ^postgres
* o chequeando el status, si lo esta, nos mostrara el process ID:
/etc/init.d/postgresql-9.1 status
pg_ctl: server is running (PID: 4449)
nos indica el PID del servidor que esta levantado contra el cluster.
si no, muestra algo similar a lo siguiente:
root@3ODI-009:/# /etc/init.d/postgresql-9.1 status
bash: /etc/init.d/postgresql-9.1: No existe el archivo o el directorio
2.- nos movemos al directorio donde se encuentre, en mi caso está en el escritorio
cd /home/usuario/Escritorio
- lo hacemos ejecutable
chmod +x postgresql-9.1.4-1-linux-x64.run
(ejecutar la versión de 32 bits o la de 64 dependiendo del sistema operativo instalado)
- lo ejecutamos
sudo ./postgresql-9.1.4-1-linux-x64.run
Clic aquí para mostrar/ocultar imágenes de la instalación
- Se inicia el proceso de configuración previo al de instalación:
- seleccionamos la ruta donde instalaremos
PostgreSQL, por defecto lo envía a
/opt/
- seleccionamos la ruta donde se instalará el clúster (nuestro directorio de datos):
- se introduce la contraseña que tendrá el usuario
postgres:
- se setea el puerto que usara el servidor:
- se selecciona la configuración regional o se deja la que viene por defecto:
-se inicia el proceso de instalación:
-esperamos que culmine..
- listo!!
- luego de que termina el proceso de instalación, se inicia el servidor y se crea el desinstalador (
uninstall-postgresql)
-
Directorio de instalación: si nos vamos al directorio donde instalamos el servidor, veremos lo siguiente:
root@3ODI-009:~# ls /opt/PostgreSQL/9.1
bin doc installer pgAdmin3 scripts stackbuilder
data include lib pg_env.sh share uninstall-postgresql
- veamos una descripción de los directorios en
/opt/PostgreSQL/9.1:
- bin: almacena los archivos ejecutables del sistema, psql, postgres, pg_ctl, etc.
- doc: documentación del sistema.
- include: almacena archivos (de extensión .h) para C/C++
- lib: librerías del sistema
- man: manuales de los comandos
- share: archivos adicionales
- data: donde reside el cluster de PostgreSQL
-
el cluster:
root@3ODI-009:~# ls /opt/PostgreSQL/9.1/data
base pg_hba.conf pg_multixact pg_stat_tmp pg_twophase postgresql.conf
global pg_ident.conf pg_notify pg_subtrans PG_VERSION postmaster.opts
pg_clog pg_log pg_serial pg_tblspc pg_xlog postmaster.pid
dos archivos que tocaremos mucho ya sea para configurar
PostgreSQL o el nivel de acceso, serán
postgresql.conf y
pg_hba.conf respectivamente.
-
postgresql.conf: define la configuración por defecto del servidor
- puerto de escucha
- parámetros de uso de memoria
- configuración del log
- configuración del idioma
- etc.
pg_hba.conf: permite restringir el acceso según:
- dirección IP del cliente.
- bases de Datos.
- nombre de usuarios y grupos.
- Requiere un reload para los cambios.
-
Los binarios:
root@3ODI-009:~# ls /opt/PostgreSQL/9.1/bin/
clusterdb ecpg pg_controldata pg_test_fsync psql
createdb initdb pg_ctl pg_upgrade psql.bin
createlang oid2name pg_dump pltcl_delmod reindexdb
createuser pg_archivecleanup pg_dumpall pltcl_listmod vacuumdb
dropdb pg_basebackup pg_resetxlog pltcl_loadmod vacuumlo
droplang pgbench pg_restore postgres
dropuser pg_config pg_standby postmaster
psql es el cliente interactivo de línea de comandos de
PostgreSQL.
Luego de que termina la instalación, podemos acceder a
psql colocando la ruta donde se encuentra instalado e indicandole con que usuario deseamos loguearnos:
/opt/PostgreSQL/9.1/bin/psql -U postgres
es necesario declarar las variables de entorno requeridas por
PostgreSQL, para eso, editamos el archivo de configuración del interprete de comandos (
.bashrc) y conseguiremos no sólo lo primero, sino, poder acceder a
psql colocando unicamente
"psql" en la consola y el
password del usuario por defecto.
¿Qué pasa si coloco psql en la consola sin haber editado el .bashrc?hay que indicarle al interprete de comandos donde se encuentra el
psql instalado o nos mostrará un bonito mensaje:
root@3ODI-009:~# psql
El programa «psql» no está instalado. Puede instalarlo escribiendo:
apt-get install postgresql-client-common
en este caso, el
psql si se encuentra instalado, pero el interprete de comandos no sabe donde se encuentra, así que (en el caso de Ubuntu) nos vamos a
/home/tu_usuario/, y presionamos
CTRL+H, o nos vamos a
menú -> ver -> mostrar los archivos ocultos y buscamos el archivo
.bashrc.
.bashrc: es el archivo de configuración de la terminal, se ejecuta cuando abrimos la consola, en el podemos indicar entre otras cosas, atajos a determinados comandos, automatizar procesos, etc.
si no encuentras el archivo
.bashrc en la carpeta indicada, no hay problema, creamos uno nuevo, abrimos el
gedit y agregamos la siguiente linea:
# le indicamos donde están nuestras variables de entorno
. /opt/PostgreSQL/9.1/pg_env.sh
guardamos y listo, como hemos editado el archivo de configuración, ahora debemos cerrar la terminal y abrirla de nuevo para poder correr los cambios, así que lo hacemos y continuamos:
root@3ODI-009:~# psql
Password:
psql.bin (9.1.4)
Type "help" for help.
postgres=#
ya podemos interactuar con
PostgreSQL a través del cliente
psql.
Dentro del
pg_env.sh encontraremos algo similar a lo siguiente:
#!/bin/sh
# The script sets environment variables helpful for PostgreSQL
export PATH=/opt/PostgreSQL/9.1/bin:$PATH
export PGDATA=/opt/PostgreSQL/9.1/data
export PGDATABASE=postgres
export PGUSER=postgres
export PGPORT=5432
export PGLOCALEDIR=/opt/PostgreSQL/9.1/share/locale
export MANPATH=$MANPATH:/opt/PostgreSQL/9.1/share/man
al tener las variables definidas en el
pg_env.sh, nos evitamos tener que exportarlas siempre que sean requeridas, en cualquier momento se puede acceder a su contenido con un simple
echo:
root@3ODI-009:~# echo $PGDATA;
/opt/PostgreSQL/9.1/data
Fuentes:
http://www.postgresql.org/
http://es.wikipedia.org/wiki/PostgreSQL
Uno de los requerimientos más solicitados en el módulo de un sistema, son los reportes, a continuación dejo una forma de generar un pequeño reporte en
PDF usando
TCPDF.
1.-
Descargamos TCPDF de la página oficial (para el ejemplo descargue
tcpdf_5_9_165.zip).
2.- Creamos una carpeta en la raíz de nuestro proyecto de
CodeIgniter, con el nombre de
plugins.
CodeIgniter
-> application
-> system
-> plugins (la nueva carpeta)
-> imagenes
3.- Descomprimimos el archivo descargado(TCPDF) en la carpeta
plugins.
4.- Usando el plugin:
a.- creamos nuestro controlador(
index_c.php):
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
xclass Index_c extends CI_Controller {
public function __construct(){
parent::__construct();
$this->load->model('index_m','modelo');
}
function index(){
$this->load->view('index_v');
}
public function generar_pdf(){
// enviamos el cabezal de la tabla
$arrHeading = array('Id', 'Campo');
// obtenemos los datos resultantes de la consulta
$arrData = $this->modelo->get_data_pdf();
// enviaremos el titulo
$sTitulo = 'Ejemplo PDF Export en CodeIgniter';
// generamos el pdf
generar_pdf($arrHeading,$arrData,$sTitulo);
}
}
b.- creamos nuestro modelo(
index_m.php):
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
xclass Index_m extends CI_Model {
public function __construct(){
parent::__construct();
}
function get_data_pdf(){
$result = $this->db
->query('SELECT idtabla1, campo1 FROM tabla1');
// recuerda que puiedes hacer cualquier filtro usando SQL
// como limitar el numero de registros, mostrar todo en mayúscula, etc..
$arrDatos=array();
foreach ($result->result_array() as $row){
$arrDatos[] = array(
htmlspecialchars($row['idtabla1'],ENT_QUOTES),
htmlspecialchars($row['campo1'],ENT_QUOTES),
);
}
$result->free_result();
$this->db->close();
return($arrDatos);
}
}
c.- nuestra vista (
index_v.php):
<?php
echo '<a title="Click aquí para exportar a PDF" href="'
.base_url() . '/index.php/index_c/generar_pdf"><img src="'
.base_url() . 'imagenes/pdf.png" alt="PDF"
width="16" height="16" /></a>';
d.- ahora debemos crear la función que se encarga de generar el PDF, lo ideal es tener esa función disponible siempre que deseemos hacer uso de ella y que sea una sola y no que este repetida en cada controlador, así que la guardaremos en nuestro propio helper. Nos vamos a
CodeIgniter --> system -->helpers y creamos un archivo con el nombre
mod_ppal_helper.php y agregamos lo siguiente:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if ( ! function_exists('generar_pdf'))
{
function generar_pdf($arrHeading,$arrData,$sTitulo){
// validamos los priemros dos parametros
if(!is_array($arrHeading) or !is_array($arrData)){
return 0;
}
// seteamos el titulo, si es necesario
$sTitulo = empty($sTitulo) ? 'NO SE HA DEFINIDO EL TITULO..' : $sTitulo;
//instanciamos al objeto codeigniter
$CI =& get_instance();
$CI->load->library('table');
// configuraciones de la tabla
$tmpl = array('table_open' => '<table border="0" cellpadding="2" cellspacing="1">');
$CI->table->set_template($tmpl);
$CI->table->set_heading($arrHeading);
// iniciamos el HTML que enviaremos para generar el PDF
$html = "<html><head>
<xstyle>
h1{
font-family: times new roman;
font-size: 50px;
text-align:center;
}
table {
color: #fff;
font-weight: bold;
font-family: Arial Black;
font-size: 28px;
background-color: #B10020;
border: red 0px solid;
}
table td {
font-weight: none;
color: #000;
background-color: #FAFAFA;
font-size: 26px;
font-family: times new roman;
}
</xstyle>
</head><body><h1>$sTitulo</h1>";
$html .= $CI->table->generate($arrData);
$html .= '</body></html>';
// para evitar errores, limpiamos,
// deshabilitamos los búferes de salida
if(ob_get_contents()){
ob_end_clean();
}
// incluimos el plugin
require_once('./plugins/tcpdf/config/lang/spa.php');
require_once('./plugins/tcpdf/tcpdf.php');
// estas son las configuraciones para la generacion del PDF
// los detalles los encuentras en la pagina oficial
$pdf = new TCPDF(PDF_PAGE_ORIENTATION,PDF_UNIT,PDF_PAGE_FORMAT,true,'UTF-8',false);
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('aqui_tu_nombre');
$pdf->SetTitle($sTitulo);
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 001');
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
$pdf->setLanguageArray($l);
$pdf->setFontSubsetting(true);
$pdf->SetFont('dejavusans', '', 12, '', true);
$pdf->AddPage();
$pdf->writeHTML($html, true, false, true, false, '');
$pdf->Output('','D');
}
}
# END Mod Ppal Class
/* End of file mod_ppal_helper.php */
/* Location: ./system/libraries/Mod_ppal.php */
e.- La configuración de la base de datos no tiene mayor misterio (
CodeIgniter --> appliction --> config --> database.php):
$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'tu_usuario';
$db['default']['password'] = 'tu_password';
$db['default']['database'] = 'el_nombre_de_tu_base_de_datos';
Las librerías y los helpers los cargas como mejor te parezca, ya sea desde cada controlador o el autoload (
CodeIgniter --> appliction --> config --> autoload.php):
// para la base de datos
$autoload['libraries'] = array('database');
// url: para base_url()
// mod_ppal: para generar_pdf()
$autoload['helper'] = array('url','mod_ppal');
El código está lo suficientemente comentado, por lo que no veo la necesidad de explicar más, cualquier duda no dudes en consultar. No olvides agregar la imagen (

) a utilizar en (
CodeIgniter --> imagenes).

Hace un tiempito hablamos de una manera rápida y básica de armar la
autenticación de usuarios en CodeIgniter(CI), esto se puede mejorar mucho, la idea es almacenar las sesiones en la base de datos para las validaciones constantes de la sesión, que realizaría un proceso vigilante.
- La base de datos:En el
post inicial ya tenemos una estructura de base de datos, una tabla
usuarios y una de
tipo de usuarios.
CI nos permite salvar las sesiones automáticamente en tablas (si se lo indicamos), para ello debemos crearla previamente:
CREATE TABLE IF NOT EXISTS ci_sesion (
session_id varchar(40) DEFAULT '0' NOT NULL,
ip_address varchar(16) DEFAULT '0' NOT NULL,
user_agent varchar(120) NOT NULL,
last_activity int(10) unsigned DEFAULT 0 NOT NULL,
user_data text NOT NULL,
PRIMARY KEY (session_id)
);
Configuramos la sesión, nos vamos a
codeigniter --> application --> config --> config.php
Clic aquí para mostrar/ocultar el código
// El nombre que quiere que la cookie de sesión sea guardada.
$config['sess_cookie_name'] = 'ci_session';
// El número de segundos que quiere que dure la sesión.
$config['sess_expiration'] = 7200;
// Si la sesión expira al cerrar el navegador
$config['sess_expire_on_close'] = TRUE;
// Si encriptar o no los datos de sesión.
$config['sess_encrypt_cookie'] = FALSE;
// Si guardar los datos de sesión a una base de datos.
// Debe crear la tabla antes de habilitar esta opción.
$config['sess_use_database'] = TRUE;
// El nombre de la tabla de sesión en la base de datos
// Debe ser un nombre de tabla válido en SQL
$config['sess_table_name'] = 'ci_sesion';
// Se indica que valide si coincide la dirección de IP
// del usuario cuando se lean los datos de sesión.
// Si la IP es dinámica y se requiere una sesión ilimitada
// deberá establecerlo a FALSE.
$config['sess_match_ip'] = FALSE;
// Si coincide el Agente del Usuario cuando se leen
// los datos de sesión.
$config['sess_match_useragent'] = TRUE;
// Indica cuan a menudo la clase de sesión se regenerará
// y creará un nuevo identificador de sesión.
$config['sess_time_to_update'] = 300;
// indicamos si queremos controlar el
// tiempo limite de expiracion al iniciar sesion
$config['sess_use_time_expire'] = TRUE;
Fíjate en el ultimo elemento:
$config['sess_use_time_expire'], ahí indicamos si deseamos o no que el usuario inserte el tiempo limite de la sesión (al loguearse), por defecto cargara el tiempo establecido en
$config['sess_expiration'], si
sess_use_time_expire se setea a
FALSE, entonces no se le pedira al usuario un tiempo de expiración y se dejara a CI encargarse de eso (tomando en consideración el tiempo establecido en el elemento
sess_expiration).
- Aplicando los hooks a nuestras sesiones:En CI podemos trabajar con
hooks, lo que nos permite disparar rutinas en momentos específicos del sistema:
pre_system: se dispara al principio de la ejecución del sistema.
pre_controller: se dispara antes de cargar el controlador.
post_controller_constructor: se dispara luego de cargar el constructor del controlador (recordemos que el constructor de una clase es lo primero que se ejecuta en ella).
post_controller: se dispara luego de que el controlador se haya cargado.
post_system: se dispara al final de la ejecución del sistema.
A nosotros nos interesa ejecutar nuestro proceso de validación de sesión, luego de que se cargue el constructor del controlador donde estemos en ese momento, así que usaremos
post_controller_constructor, editamos el archivo
hook.php, nos vamos a
codeigniter --> application --> config --> hook.php y agregamos lo siguiente:
hook.php:
$hook['post_controller_constructor'] = array(
'xclass' => 'gestion_sesion', // clase que controla la sesion
'function' => 'index', // metodo encargado de todo, dentro de la clase
'filename' => 'gestion_sesion.php', // archivo a cargar
'filepath' => 'hooks' // carpeta donde se encuentra la clase
);
Ahora debemos crear la clase, nos vamos a
codeigniter --> application --> hooks y creamos un archivo con el nombre
gestion_sesion.php que es el que asignamos:
gestion_sesion.php:
Clic aquí para mostrar/ocultar el código
<?php
xclass Gestion_sesion{
function index(){
//instanciamos al objeto codeigniter
$CI =& get_instance();
// obtenemos el nombre del controlador en el que estamos
$controlador = $CI->router->xclass;
// indicamos los controladores que pueden ver por defecto los visitantes
$controladores_guest = array('index_c','login_c');
// si la sesion se inicio y el usuario intenta entrar a login_c,
// lo enviamos al index
if(user_is_logged() && $controlador=='login_c'){
redirect('index_c');
// si el usuario es un visitante,
// solo puede entrar a los controladores permitidos para él..
}elseif(!user_is_logged() &&
(!in_array($controlador,$controladores_guest))){
redirect('login_c');
// cerramos la sesion si el tiempo establecido expiro
// solo si se cambio el tiempo de expiracion
}elseif($CI->config->item('sess_use_time_expire')){
// cargamos la libreria de sesion
$CI->load->library('session');
$arrSesion = $CI->session->userdata('ses_usuario');
if (is_array($arrSesion) and $arrSesion['seslimite']<=time()){
cerrar_sesion();
}
}
unset($CI);
}
}
?>
Por ultimo en esto de los hooks, hay que indicarle a CI que deseamos que se apliquen estos cambios, así que nos vamos a
codeigniter --> application --> config --> config.php y donde dice:
$config['enable_hooks'] = FALSE;
lo cambiamos por:
$config['enable_hooks'] = TRUE;
En la clase
gestion_sesion.php hacemos uso de unas funciones que no son nativas de PHP, así que creamos nuestro propio
helper(asistente) y ahí las incluimos, esto lo hacemos así porque al ser un asistente, podemos acceder a esas funciones cuando lo necesitemos. Nos vamos a
codeigniter --> system -->helpers y ahí creamos un archivo de nombre
mod_ppal_helper.php, puedes usar cualquier otro nombre, pero deja el sufijo
_helper, dentro del archivo incluimos nuestras funciones:
mod_ppal_helper.php:
Clic aquí para mostrar/ocultar el código
<?php
# determina si el usuario esta logueado o no..
if ( ! function_exists('user_is_logged'))
{
function user_is_logged(){
//instanciamos al objeto codeigniter
$CI =& get_instance();
// cargamos la base de datos
$CI->load->database('default');
// obtenemos el valor del item 'sess_use_database'
$sess_use_database = $CI->config->item('sess_use_database');
// cargamos la libreria de sesion
$CI->load->library('session');
// obtenemos los datos de la sesion
$arrSesion = $CI->session->userdata('ses_usuario');
// si no esta definida la sesion, no esta logueado
if (!isset($arrSesion['usuario'])){
return false;// indicamos no is_logged
}else{
// obtenemos el id del usuario
$session_id = $CI->session->userdata('session_id');
// si se usa la session database, debemos asegurarnos
// de que la sesion en el cliente, coincida con
// la sesion de la base de datos
if (!empty($session_id) and $sess_use_database){
// consultamos por id
$CI->db->from('ci_sesion');
$CI->db->where('session_id',$session_id);
$query = $CI->db->get();
// si coincide el session_id en algun registro
// es porque el usuario tiene sesion abierta
return ($query->num_rows()>0) ? true : false;
}else{
//
return (!empty($session_id)) ? true : false;
}
}
$CI->db->close();
unset($CI);
}
}
# permite cerrar la sesion activa ..
if (! function_exists('cerrar_sesion')){
function cerrar_sesion(){
//instanciamos al objeto codeigniter
$CI =& get_instance();
// cargamos la base de datos
$CI->load->database('default');
// obtenemos el valor del item 'sess_use_database'
$sess_use_database = $CI->config->item('sess_use_database');
// si el usuario esta logueado, cerramos la sesion..
if (user_is_logged()){
// cargamos la libreria sesion
$CI->load->library('session');
// si se esta usando la base de datos para las sesiones
if($sess_use_database){
//exit('entre, esta logueado y se usa db');
// indicara si se elimino la seison de la db
$delete = false;
// obtenemos los datos de la sesion
$arrSesion = $CI->session->userdata('ses_usuario');
// obtenemos los registros de sesion
$CI->db->select('user_data,session_id');
$CI->db->from('ci_sesion');
$query = $CI->db->get();
$arrDatos = array();
// recorremos la lista de usuarios con sesion en la db
foreach($query->result() as $row){
// obtenemos el user_data de la fila
$valor = $row->user_data;
// los datos estan serializados en la db
// asi que los deserializamos
$arrData = unserialize($valor);
// verificamos si el usuario pasado por parametro
// es el mismo q tiene la sesion abierta
if ($arrSesion['usuario']==$arrData['ses_usuario']['usuario']){
// borramos la sesion de la db
$CI->db->delete('ci_sesion',array('session_id' => $row->session_id));
//echo $CI->db->last_query();exit;
$delete = true;
break;
}
}
if($delete){
// cerramos la sesion
$CI->session->sess_destroy();
}
}else{
// cerramos la sesión
$CI->session->sess_destroy();
}
}
// adicionalmente verificamos las sesioens activas en la db
// y eliminamos las que tengan determinado tiempo de incactividad
$CI->db->where('last_activity <',(time() - 3600));//3600 - 1 hora
$CI->db->delete('ci_sesion');
$CI->db->close();
#-----------------------------------------------------------------------
unset($CI);
// redireccionamos al controlador index
redirect('index_c', 'location');
}
}
?>
Ahora le indicamos a CI que cargue por defecto nuestro helper, ya que son funciones de uso común. En
codeigniter --> application --> config --> autoload.php agregamos el helper al array:
$autoload['helper'] = array('url');nos quedaría así:
$autoload['helper'] = array('url','mod_ppal');
Resulta lógico que, si al momento de que se carga el sitio Web en lugar de descargar veinte (20) imágenes para armar la plantilla, se descarga una (1) sola, el tiempo trascurrido se reducirá notablemente. El
CSS Sprites, es una técnica que consiste en la carga de una única imagen que alberga cada uno de los diseños requeridos para formar o decorar la plantilla y acceder a cada imagen por su posición (x+y).
El truco consiste en el uso de las propiedades
background-image (para la carga) y
background-position para posicionarse dentro de la imagen y mostrar lo que realmente se desea.
div.pos{
width: 20px;
float: left;
margin-right: 10px;
margin-top: -10px;
}
#img1, #img2, #img3, #img4, #img5, #img6 {
width: 16px;/* el ancho de cada imagen */
height: 16px; /* el alto de cada imagen*/
background-image: url('http://1.bp.blogspot.com/-HQFo-qvL1Wc/T8qutCOwr3I/AAAAAAAAASA/PVWgL7s1uCc/s200/imagen.png');
background-repeat: no-repeat;
}
#img1 {
background-position: -0px -0px;
}
#img2 {
background-position: -0px -26px;
}
#img3 {
background-position: -0px -52px;
}
#img4 {
background-position: -0px -78px;
}
#img5 {
background-position: -0px -104px;
}
#img6 {
background-position: -0px -130px;
}
#img7 {
background-position: -0px -78px;
}
<xstyle>
.img1, .img2, .img3, .img4, .img5, .img6 {
width: 16px;/* el ancho de cada imagen */
height: 16px; /* el alto de cada imagen*/
background-image: url('imagen.png');
background-repeat: no-repeat;
}
.img1 {
background-position: -0px -0px;
}
.img2 {
background-position: -0px -26px;
}
.img3 {
background-position: -0px -52px;
}
.img4 {
background-position: -0px -78px;
}
.img5 {
background-position: -0px -104px;
}
.img6 {
background-position: -0px -130px;
}
.img7 {
background-position: -0px -78px;
}
</xstyle>
<p xclass='img1'></p>
<p xclass='img2'></p>
<p xclass='img3'></p>
<p xclass='img4'></p>
<p xclass='img5'></p>
<p xclass='img6'></p>
<p xclass='img7'></p>
Para elaborar la imagen no es necesario abrir ningún software de diseño, en la red encontramos sitios como
CSSsprites, donde se puede generar una imagen única a partir de varias disponibles.

Al momento de agregar
Captcha a nuestros sistemas tenemos varias
opciones, una de las más interesantes, el
reCaptcha de
google.
CodeIgniter dispone de una librería fácil de usar, que permite generar estas imágenes sin complicaciones, a continuación un ejemplo de uso:
Debemos incluir la librería:
$this->load->helper('captcha');Con la función
create_captcha() generamos la imagen personalizada, recibe como parámetro un
array con las especificaciones. ejemplo:
$arrCaptcha = array(
//
//'word' => ''//indica la palabra que aparecerá en la imagen,
// por defecto genera aleatoriamente
// ruta y nombre de la carpeta que almacenara las imagenes
'img_path' => './captcha/',
// direccion web donde se encuentraran alojadas las imagenes
'img_url' => base_url().'captcha/',
// ruta donde se encuentra el font a usar en la imagen
'font_path' => './system/fonts/texb.ttf',
// ancho de la imagen en pixeles
'img_width' => '150',
// alto de la imagen
'img_height' => '30',
// tiempo en segundos para eliminar la imagen generada de la carpeta
// 3600 es una hora
'expiration' => '3600'
);
// generamos el captcha
$captcha = create_captcha($arrCaptcha);
Luego de generar el captcha, disponemos de un array con los siguientes datos:
Array
(
[word] => el código que contiene la imagen
[time] => el tiempo de cuando fue generada [TIMESTAMP (in microtime)]
[image] => el código html de la imagen
)
Para poder generar el captcha, el servidor debe cumplir con los siguientes requerimientos y especificaciones:
- es necesario tener instalada la
librería GD (
ejemplo para Debian/Ubuntu).
- para crear el captcha son requeridas las propiedades
img_path y
img_url.
- si no se indica una cadena de caracteres en la propiedad
word, entonces se generara una cadena aleatoria.
- si no se especifica una ruta de acceso a la carpeta que alberga los
font, se usara la fuente de la GD.
- la carpeta
captcha debe tener permisos de escritura (666 o 777).
A continuación el código de ejemplo utilizado:
Controlador: captcha_c.php
(clic para mostrar/ocultar).
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
xclass Captcha_c extends CI_Controller {
public function __construct(){
parent::__construct();
// cargamos el asistente de captcha y url
$this->load->helper(array('captcha','url'));
// usaremos librerias para sesion y validacion de formulario
$this->load->library(array('form_validation','session'));
}
function index(){
$arrValidaciones = array(
array(
'field' => 'txtUsuario',
'label' => 'Usuario',
'rules' => 'required'
),
array(
'field' => 'txtCodeImg',
'label' => 'código de imagen',
'rules' => 'required|callback__valida_captcha'
)
);
// establecemos las reglas de validacion
$this->form_validation->set_rules($arrValidaciones);
// indicamos que los errores se les aplique la clase .. (CSS)
$this->form_validation->set_error_delimiters('<span id="msj_error"> * ','</span>');
if ($this->form_validation->run() == FALSE){
$arrCaptcha = array(
'img_path' => './captcha/',
'img_url' => base_url().'captcha/',
'font_path' => './system/fonts/texb.ttf',
'img_width' => '150',
'img_height' => '30',
'expiration' => '3600'
);
// generamos el captcha
$captcha = create_captcha($arrCaptcha);
//echo '<pre>',print_r($captcha),'</pre>';exit;
// enviaremos la imagen generada
$arrDatos['imagen']= $captcha['image'];
// guardamos en la sesion la cadena generada
$this->session->set_userdata('code_captcha',$captcha['word']);
// cargamos la vista
$this->load->view('captcha_v',$arrDatos);
}else{
echo "El código introducido es correcto!!";
}
}
function _valida_captcha($code_usuario){
// obtenemos el codigo almacenaod en la sesion
$code_generado = $this->session->userdata('code_captcha');
// -----------------------------------------------------------
// si deseamos que la comparacion sea case sensitive
// comentatamos las siguientes dos lineas..
$code_usuario = strtolower($code_usuario);
$code_generado = strtolower($code_generado);
// -----------------------------------------------------------
// comparamos ..
if (empty($code_usuario) or $code_usuario<>$code_generado){
$this->form_validation->set_message('_valida_captcha',
'El código introducido es incorrecto!!');
return FALSE;
}else{
return TRUE;
}
}
}
/* End of file captcha_c.php */
/* Location: ./application/controllers/captcha_c.php */
Vista: captcha_v.php
(clic para mostrar/ocultar).
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8" />
<title>Captcha en CodeIgniter</title>
<xstyle type="text/css">
body {
background-color: #fff;
margin: 40px;
font: 13px/20px normal Helvetica, Arial, sans-serif;
color: #4F5155;
}
h1 {
color: #444;
background-color: transparent;
border-bottom: 1px solid #D0D0D0;
font-size: 19px;
font-weight: normal;
margin: 0 0 14px 0;
padding: 14px 15px 10px 15px;
}
#body{
margin: 0 15px 0 15px;
}
#container{
margin: 10px;
border: 1px solid #D0D0D0;
-webkit-box-shadow: 0 0 8px #D0D0D0;
}
form #msj_error {
font-size: 12px;
color: red;
}
label{
font-weight: bold;
width: 100px;
}
</xstyle>
</head>
<body>
<div id="container">
<h1>Captcha en CodeIgniter!</h1>
<div id="body">
<?php
// esto imprime la etiqueta <form method="post" ...
echo form_open('captcha_c/index',array('id' => 'form_captcha'));
// armamos los campos
$txtUsuario = array(
'name' => 'txtUsuario',
'id' => 'txtUsuario',
'maxlength' => '20',
'size' => '20',
'value' => set_value('txtUsuario')
);
$txtCodeImg = array(
'name' => 'txtCodeImg',
'id' => 'txtCodeImg',
'maxlength' => '20',
'size' => '20',
'value' => set_value('txtCodeImg')
);
$btSubmit = array(
'name' => 'btSubmit',
'id' => 'btSubmit',
'value' => 'Validar',
);
// usuario
echo '<p>',form_label('Nombre de usuario: '),form_input($txtUsuario)
,form_error('txtUsuario'),'</p>';
// la imagen captcha
echo '<p>',$imagen,'</p>';
// input para el codigo de la imagen
echo '<p>',form_label('Código de la imagen: '),form_input($txtCodeImg)
,form_error('txtCodeImg'),'</p>';
// botones de accion
echo '<p>',form_submit($btSubmit),'</p>';
// cerramos el tag form
echo form_close();// </from>
?>
</div>
</div>
</body>
</html>
En el ejemplo se usan
sesiones, pero también puede usarse una tabla de la base de datos para almacenar la cadena de caracteres generada y validar correctamente al enviar el formulario.
Documentación en inglesCómo usar
sesiones tradicionales en Codeigniter.

El uso de tablas para presentar los datos ha ganado relevancia con los años desde la versión 3 de
HTML, permitiendo hacer divisiones en filas y columnas, lo que facilita ordenar, visualizar rápida y fácilmente la información.
En
icant.co.uk encontramos una interesante galería con diferentes y muy variados estilos, listos para usar.
table {
width: 100%;
border:1px solid #000000;
border-spacing: 0px; }
table a, table, tbody, tfoot, tr, th, td {
font-family: Arial, Helvetica, sans-serif;
}
table caption {
font-size: 1.8em;
text-align: left;
text-indent: 100px;
background: url(http://www.consulting1x1.com/csstg/images/bg_caption.gif) left top;
height: 40px;
color: #FFFFFF;
border:1px solid #000000; }
thead th {
background: url(http://www.consulting1x1.com/csstg/images/bg_th.gif) left;
height: 21px;
color: #FFFFFF;
font-size: 0.8em;
font-family: Arial;
font-weight: bold;
padding: 0px 7px;
margin: 20px 0px 0px;
text-align: left; }
tbody tr { background: #ffffff; }
tbody tr.odd { background: #f0f0f0; }
tbody th {
background: url(http://www.consulting1x1.com/csstg/images/arrow_white.gif) left center no-repeat;
background-position: 5px;
padding-left: 40px !important; }
tbody tr.odd th {
background: url(http://www.consulting1x1.com/csstg/images/arrow_grey.gif) left center no-repeat;
background-position: 5px;
padding-left: 40px !important; }
tbody th, tbody td {
font-size: 0.8em;
line-height: 1.4em;
font-family: Arial, Helvetica, sans-serif;
color: #000000;
padding: 10px 7px;
border-bottom: 1px solid #800000;
text-align: left; }
tbody a {
color: #000000;
font-weight: bold;
text-decoration: none; }
tbody a:hover {
color: #ffffff;
text-decoration: underline; }
tbody tr:hover th {
background: #800000 url(http://www.consulting1x1.com/csstg/images/arrow_red.gif) left center no-repeat;
background-position: 5px;
color: #ffffff; }
tbody tr.odd:hover th {
background: #000000 url(http://www.consulting1x1.com/csstg/images/arrow_black.gif) left center no-repeat;
background-position: 5px;
color: #ffffff; }
tbody tr:hover th a, tr.odd:hover th a {
color: #ffffff; }
tbody tr:hover td, tr:hover td a, tr.odd:hover td, tr.odd:hover td a {
background: #800000;
color: #ffffff; }
tbody tr.odd:hover td, tr.odd:hover td a{
background: #000000;
color: #ffffff; }
tfoot th, tfoot td {
background: #ffffff url(http://www.consulting1x1.com/csstg/images/bg_footer.gif) repeat-x bottom;
font-size: 0.8em;
color: #ffffff;
height: 21px;
}
Ejemplo de tabla
| Apellido | Nombres | Ciudad | Fecha nacimiento | Comentario |
| Total | 5 filas |
Pacheco |
Ana María | Maracaibo | 1992-11-24 | |
Ramirez |
Cecilia Ines | Caracas | 1990-02-24 | Falta por entregar documentos.. |
Arjona |
Ricardo Fernando | Valencia | 1985-12-03 | No, no es el cantante :s |
Cassano |
Marco Antonio | Barcelona | 1981-12-12 | |
Martín |
María Camino | Barcelona | 1990-07-03 | uhm.. =) |
Ir a la Galería
Ya habíamos hablado del
JCombo, plugin de
Jquery que permite anidar facilmente elementos select, es decir, disponer de combos dependientes. A continuación un ejemplo de uso con
CodeIgniter.
Modelo: jcombo_m.php
(clic para mostrar/ocultar código).
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
xclass Jcombo_m extends CI_model{
function __construct(){
parent::__construct();
$this->load->database();
}
public function get_paises(){
$query = $this->db
->query("SELECT id_country AS id, country_name AS descripcion
FROM countries ORDER BY descripcion ASC");
if($query->num_rows()>0){
$arrDatos = array();
foreach($query->result() as $row){
$arrDatos[] = array(
htmlspecialchars($row->id,ENT_QUOTES),
htmlspecialchars($row->descripcion,ENT_QUOTES)
);
}
$query->free_result();
// devolver los datos en json
return json_encode($arrDatos);
}else{
return json_encode(array(1=> array("-- no se encontraron registros..")));
}
}
public function get_ciudades($id){
if(empty($id) or !ctype_digit($id)) return false;
$query = $this->db
->query("SELECT id_city AS id, city_name AS descripcion
FROM cities WHERE id_country=?
ORDER BY descripcion ASC",array($id));
if($query->num_rows()>0){
$arrDatos = array();
foreach($query->result() as $row){
$arrDatos[] = array(
htmlspecialchars($row->id,ENT_QUOTES),
htmlspecialchars($row->descripcion,ENT_QUOTES)
);
}
$query->free_result();
// devolver los datos en json
return json_encode($arrDatos);
}else{
return json_encode(array(1=> array("-- no se encontraron registros..")));
}
}
public function get_zonas($id){
if(empty($id) or !ctype_digit($id)) return false;
$query = $this->db
->query("SELECT id_zone AS id, zone_name AS descripcion
FROM zones WHERE id_city=?
ORDER BY descripcion ASC",array($id));
if($query->num_rows()>0){
$arrDatos = array();
foreach($query->result() as $row){
$arrDatos[] = array(
htmlspecialchars($row->id,ENT_QUOTES),
htmlspecialchars($row->descripcion,ENT_QUOTES)
);
}
$query->free_result();
// devolver los datos en json
return json_encode($arrDatos);
}else{
return json_encode(array(1=> array("-- no se encontraron registros..")));
}
}
}
Controlador: jcombo_c.php
(clic para mostrar/ocultar código).
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
xclass Jcombo_c extends CI_Controller {
function __construct() {
parent::__construct();
$this->load->model('jcombo_m','modelo');
$this->load->helper('url');
$this->load->helper('form');
}
public function index($submit=false){
$arrDatos['sTitulo'] = 'JCombo en CodeIgniter';
$arrDatos['submit'] = $submit;
// si se envio el formulaario..
if($submit){
$arrDatos['id_pais'] = $this->input->post('selPaises');
$arrDatos['id_ciudad'] = $this->input->post('selCiudades');
$arrDatos['id_zona'] = $this->input->post('selZonas');
}
$this->load->view('jcombo_v',$arrDatos);
}
public function get_paises(){
# para este caso particular,
# es necesario imprimir aqui en el controlador..
echo $this->modelo->get_paises();
}
public function get_ciudades($id){
echo $this->modelo->get_ciudades($id);
}
public function get_zonas($id){
echo $this->modelo->get_zonas($id);
}
}
/* End of file jcombo_c.php */
/* Location: ./application/controllers/jcombo_c.php */
Vista: jcombo_v.php
(clic para mostrar/ocultar código).
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<title><?php echo $sTitulo; ?></title>
<!-- incluimos el plugin (jcombo) y el jquery-->
<script type="text/javascript" src="<?php echo base_url(); ?>/js/jquery.js"></script>
<script type="text/javascript" src="<?php echo base_url();
?>/js/jcombo/jquery.jCombo.min.js"></script>
<!-- configuramos el plugin-->
<script type="text/javascript">
$(function() {
// paises es el primer select a llenar<pre xclass='brush:xml'>
$("#selPaises").jCombo(
"<?php echo base_url(); ?>index.php/jcombo_c/get_paises",{
selected_value: "<?php echo empty($id_pais) ? 0 : $id_pais; ?>",
initial_text: "-- seleccione un país --"
});
$("#selCiudades").jCombo("<?php echo base_url(); ?>index.php/jcombo_c/get_ciudades/",{
parent: "#selPaises", // combo padre
selected_value: "<?php echo empty($id_ciudad) ? 0 : $id_ciudad; ?>",
initial_text: "-- seleccione una ciudad --"
});
$("#selZonas").jCombo("<?php echo base_url(); ?>index.php/jcombo_c/get_zonas/",{
parent: "#selCiudades",
selected_value: "<?php echo empty($id_zona) ? 0 : $id_zona; ?>",
initial_text: "-- seleccione una zona --"
});
});
</script>
<xstyle>
#form_ppal{
margin: 0 auto;
border: 1px dashed blue;
padding: 3px;
width: 500px;
}
#form_ppal p{
width: 100%;
font-weight: bold;
}
#form_ppal p label{
width: 70px;
font-weight: bold;
float: left;
text-align:right;
padding-right:3px;
margin-top:3px;
}
</xstyle>
</head>
<body>
<?php
echo form_open('jcombo_c/index/1',array('id'=>'form_ppal'));// <form ..
echo '<p>',form_label('Paises: ')
,form_dropdown('selPaises',array(),'','id="selPaises"'),'</p>';
echo '<p>',form_label('Ciudades: ')
,form_dropdown('selCiudades',array(),'','id="selCiudades"'),'</p>';
echo '<p>',form_label('Zonas: ')
,form_dropdown('selZonas',array(),'','id="selZonas"'),'</p>';
echo '<p>',form_label('')
,form_submit(array('id'=>'btEnviar','value'=>'Enviar')),'</p>';
// si el formulario se recargo, mostramos los datos enviados..
if ($submit){
echo '<hr/><p>id_pais: ',$id_pais,'</p>';
echo '<p>id_pais: ',$id_ciudad,'</p>';
echo '<p>id_pais: ',$id_zona,'</p>';
}
echo form_close();// </form>
?>
</body>
</html>
La explicación del plugin está en el
post citado, el script de la base de datos se encuentra en el paquete de descarga oficial. La configuración de la base de datos es igual que siempre..
application/config/database.php$db['default']['hostname'] = 'localhost';// mi servidor
$db['default']['username'] = 'root';// mi usuario en MySQl
$db['default']['password'] = '1234';// el password de mi usuario, si no tiene no se coloca..
$db['default']['database'] = 'ci_jcombo';// el nombre de mi base de datos de ejemplo
$db['default']['dbdriver'] = 'mysql';
Para el ejemplo use MySQl, pero esto no es limitante, puedes usar cualquier otro manejador de base de datos.
Cualquier duda no dudes en consultar!

Según la Wikipedia:
Los ficheros CSV (del inglés comma-separated values) son un tipo de documento en formato abierto sencillo para representar datos en forma de tabla, en las que las columnas se separan por comas (o punto y coma en donde la coma es el separador decimal...
Ejemplo:
987,juan,87345,10 norte 342
876,pedro,43649,8 oriente 342
123,jorge,03342,av. libertad 23
69,vicente,61560,valencia nº183
18,lorenzo,06490,sol nº 18
19,lucía,06480,luna nº 8
CodeIgniter permite generar archivos
CSV con muy pocos pasos, para ello cuenta con una clase (
Database Utility Class) que dispone de varias funciones utiles para trabajar con bases de datos.
Uso:cargar la clase:
$this->load->dbutil();
Una vez iniciada la clase, se puede a acceder a sus funciones, una de ellas nos permite generar texto con fotmato
CSV a partir del resultado de una consulta pasado como argumento.
$this->load->dbutil();
$query = $this->db->query("SELECT * FROM mi_tabla");
echo $this->dbutil->csv_from_result($query);
Si se desea personalizar el
CSV, podemos indicarle un delimitador diferente e incluso, los caracteres de nueva línea.
// opciones del csv
$delimitador = ";";
$nueva_linea = "\r\n";
$query = $this->db->query("SELECT * FROM $sTabla");
// generamos el csv
echo $this->dbutil->csv_from_result($query, $delimitador, $nueva_linea);
Ahora veamos un ejemplo completo: se trata de un pequeño módulo que permite descargar un archivo en formato
CSV a partir de una tabla seleccionada.
Modelo:
download_csv_m.php- clic aquí para ver el código
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
xclass Download_csv_m extends CI_Model {
function __construct(){
parent::__construct();
$this->load->database('SGA',TRUE);
}
function get_tablas($schemaname='gestion_alimentaria'){
$query = $this->db
->query("SELECT tablename FROM pg_tables
WHERE schemaname=?",$schemaname);
// si hay resultados
if ($query->num_rows()>0){
$arrDatos = array();
// almacenamos en una matriz bidimensional
foreach($query->result() as $row){
$nombre_tabla = htmlspecialchars($row->tablename,ENT_QUOTES);
$arrDatos[$nombre_tabla] = $nombre_tabla;
}
$query->free_result();
return $arrDatos;
}
}
function get_datos_tabla($sTabla,$schemaname='mi_esquema'){
if(empty($sTabla)){
return false;
}
// limpiamos los datos recibidos..
$schemaname = $this->db->escape_str($schemaname);
$sTabla = $this->db->escape_str($sTabla);
// opciones del csv
$delimitador = ";";
$nueva_linea = "\r\n";
$this->load->dbutil();
$query = $this->db->query("SELECT * FROM $schemaname.$sTabla");
// generamos el csv
return $this->dbutil->csv_from_result($query, $delimitador, $nuevalinea);
}
}
?>
Controlador:
download_csv_c.php- clic aquí para ver el código
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
xclass Download_csv_c extends CI_Controller {
public function __construct(){
parent::__construct();
$this->load->helper(array('form','download'));
$this->load->library('form_validation');
$this->load->model('download_csv_m','modelo');
}
public function index($submit=false){
// seteamos las variables principales
$datos['sSubTitulo'] = 'Generar archivo CSV';
$datos['sTitulo'] = 'mi titulo';
$datos['submit'] = $submit;
$datos['arrTablas'] = $this->modelo->get_tablas();
// si ya esta cargado, lo enviamos
if ($submit){
$datos['id_tabla'] = $this->input->post('selTablas');
}
// cargamos la interfaz
$this->load->view('download_csv_v', $datos);
}
public function validar_form(){
// armamos un array con las reglas de validacion
$arrValidaciones = array(
array(
'field' => 'selTablas',
'label' => 'Tabla',
'rules' => 'required'
)
);
// establecemos las reglas de validacion
$this->form_validation->set_rules($arrValidaciones);
// indicamos que los errores se les aplique la clase .. (CSS)
$this->form_validation
->set_error_delimiters('<span xstyle="color:red;"> * ','</span>');
// iniciamos las validaciones - solo si no se va a eliminar
if ($this->form_validation->run() == FALSE){
$this->index(true);
}else{
$sTabla = $this->input->post('selTablas');
$nombre_archivo = $sTabla.'_'.date('d-m-Y').'.csv';
$sCSV = $this->modelo->get_datos_tabla($sTabla);
// Vamos a mostrar un CSV
header('Content-type: application/csv');
header('Content-Disposition: attachment; filename="'.$nombre_archivo.'"');
// en este caso es necesario imprimir aqui mismo en el controlador
echo $sCSV;
}
}
}
?>
Vista:
download_csv_c.php- clic aquí para ver el código
<?php
echo '<html>
<head>
<title>'.$sTitulo.'</title></head>
<xstyle>
form, h1 {
margin: 0 auto;
border: dashed 1px #000;
text-align: center;
width: 300px;
}
form {
font-size: 12px;
}
h1 {
padding: 10px;
font-size: 14px;
}
</xstyle>
<body>
<h1>',$sSubTitulo,'</h1>';
// esto imprime la etiqueta <form method="post" ...
echo form_open('download_csv_c/validar_form/',array('id' => 'form_download'));
$btSubmit = array(
'name' => 'btSubmit',
'id' => 'btSubmit',
'value' => 'Generar CSV',
);
// ----------------se imprimen los campos --------------------
$selected = $submit ? $id_tabla : 0;
$atributos = ' id="selTablas"';
echo '<p>',form_label('Tabla: ')
,form_dropdown('selTablas',$arrTablas,$selected,$atributos)
,form_error('selTablas') ? ' '.form_error('selTablas') : '','</p>';
echo '<p>',form_submit($btSubmit),'</p>';
// cerramos el tag form
echo form_close();// </from>
echo '</body></html>';
?>
Nota:
para el ejemplo se uso
PostgreSQL como manejador de base de datos, éste por defecto, permite separar las tablas por esquemas.
Para probarlo con
MySQL solo bastaría cambiar en el modelo, la siguiente línea:
$query = $this->db->query("SELECT * FROM $schemaname.$sTabla");por:
$query = $this->db->query("SELECT * FROM $sTabla"); Actualización:- los que utilizen
MySQL pueden generar la lista de tablas directamente con funciones de
CodeIgniter (sólo si es requerido):
// lista las tablas de una base de datos
function get_tablas(){
// devuelve un arreglo que contiene todos los nombres de todas las tablas
// en la base de datos a la que actualmente está conectado.
$tablas = $this->db->list_tables();
$arrDatos = Array();
foreach ($tablas as $tabla){
$arrDatos[] = $tabla;
}
//
return count($arrDatos) ? $arrDatos : false;
}

Al momento de hacer las validaciones de un sistema se puede abordar de diferentes formas,
acv2 preguntaba cómo hacer las
validaciones de un elemento select con
XAJAX (
AJAX+
PHP) y, basandonos en el post
base, nos queda éste ejemplo, donde validamos un
select simple y uno de tipo
multiple:
index.php<?php
// incluimos la clase
require_once("xajax/xajax_core/xajax.inc.php");
// Creamos una instancia al objeto XAJAX:
$xajax = new xajax();
function no_valido_select($sValor){
// validamos en primer lugar,
// que se haya seleccionado una opcion
if(empty($sValor)) return '* Debe seleccionar una opción..';
# aqui cualquier otra validacion
# ...
// retorna FALSE si los datos estan perfectamente validados
return FALSE;
}
function no_valido_multi_select($arrItems){
// validamos en primer lugar,
// que se haya seleccionado una opcion
if(!is_array($arrItems) or count($arrItems)<2 or empty($arrItems[0])){
return '* Debe seleccionar al menos dos opciones sin incluir la primera..';
}
# aqui cualquier otra validacion
# ...
// retorna FALSE si los datos estan perfectamente validados
return FALSE;
}
// valida el campo pasado por parametro
function FormManage($form,$sCampo){
$sCadena = $form["sel$sCampo"];
$sMsj = '';
// iniciamos el llamado a las validaciones segun sea el caso
if (($sCampo=='Ciudades' and $sTempMsj=no_valido_select($sCadena))
or ($sCampo=='MultipleCiudades' and $sTempMsj=no_valido_multi_select($sCadena))){
$sMsj = $sTempMsj;// actualizamos
}
// creamos una nueva instancia para generar la respuesta con ajax (xajaxResponse).
$objRespuesta = new xajaxResponse();
// asignamos el valor que determinara la imagen y el mensaje a mostrar por campo
$sImg = (!empty($sMsj) ? 'incorrecto' : 'correcto');
// asignamos el codigo html para los mensajes
$sHTMLMsj = "<div xclass='DivLocal'><img border='0'
src='imagenes/$sImg.png' /> valor $sImg</div>";
$sHTMLMsjGlobal = "<div xclass='DivGlobal'><img border='0'
src='imagenes/warning.png' /> $sMsj</div>";
// Actualizamos los div
$objRespuesta->assign("div$sCampo",'innerHTML', $sHTMLMsj);
$objRespuesta->assign('DivGlobal','innerHTML',
(!(!$sMsj) ? $sHTMLMsjGlobal : ''));
// retornamos el objeto
return $objRespuesta;
}
function FormProcess($form)
{
// creamos una nueva instancia para generar la respuesta con ajax
$objRespuesta = new xajaxResponse();
// si los campos estan correctos
if(no_valido_select($form['selCiudades'])
or no_valido_multi_select($form['selMultipleCiudades']))
$objRespuesta->alert('¡El formulario debe estar perfectamente validado!');
else
{
/*
aqui iria el proceso que almacena los datos en la Base de Datos,
recuerda que los datos deben de ser filtrados por seguridad
script ...
script ....
script .....
*/
/* luego de que has hecho lo debido con los datos,
informamos al usuario del resultado
podemos hacerlo usando un DIV o bien, un alert de JavaScript
*/
$objRespuesta->alert('¡Datos almacenados correctamente!');
// limpiamos los campos
$ArrayCampos = array('Ciudades','MultipleCiudades');
//$NumCampos = count($ArrayCampos);
for ($i=0; $i<2; $i++)//no hace falta usar count puesto que sabemos cuantos campos con..
{
$objRespuesta
->clear("sel$ArrayCampos[$i]",'value') //limpiando los txt
->clear("div$ArrayCampos[$i]",'innerHTML'); //limpiando los div
}
}
return $objRespuesta;
}
$xajax->registerFunction('FormManage'); // gestiona las validaciones del formulario
$xajax->registerFunction('FormProcess'); // procesa los datos del formulario
//Le indicamos al objeto xajax que procese la peticion / el pedido
$xajax->processRequest();
?>
<html>
<head>
<title>Validando select's con XAJAX</title>
<link href="estilo.css" rel="xstylesheet" />
<?php
//se le dice que Incluya el JavaScript generado desde XAJAX
$xajax->printJavascript('xajax/');
?>
</head>
<body>
<form name='form1' id='form1' action='javascript:void(null);'
onsubmit="xajax_FormProcess(xajax.getFormValues('form1'))">
<div xclass='DivTable'>
<table border='0'>
<tr><td colspan='3'><div id='DivGlobal'></div><hr/></td></tr>
<tr>
<td align='right' width='220px' xclass='Campos'>Ciudades:</td>
<td width='200px'>
<select name="selCiudades" id="selCiudades"
onChange="xajax_FormManage(xajax.getFormValues('form1'),'Ciudades')">
<option value="">-- seleccione una ciudad--</option>
<option value="1">Barcelona</option>
<option value="2">Barquisimeto</option>
<option value="3">Caracas</option>
<option value="4">Maracaibo</option>
<option value="5">Los teques</option>
<option value="6">Valencia</option>
</select>
</td>
<td align='left' width='300px'><div id='divCiudades'></div></td>
</tr>
<tr>
<td align='right' width='220px' xclass='Campos'>Multiple Ciudades:</td>
<td width='200px'>
<select name="selMultipleCiudades[]" id="selMultipleCiudades" multiple="multiple"
onChange="xajax_FormManage(xajax.getFormValues('form1'),'MultipleCiudades')">
<option value="">-- seleccione varias ciudades--</option>
<option value="1">Barcelona</option>
<option value="2">Barquisimeto</option>
<option value="3">Caracas</option>
<option value="4">Maracaibo</option>
<option value="5">Los teques</option>
<option value="6">Valencia</option>
</select>
</td>
<td align='left' width='300px'><div id='divMultipleCiudades'></div></td>
</tr>
<tr>
<td align='center' colspan='3'><hr/>
<input type='submit' tabindex='8' value='Guardar los datos'></td>
</tr>
</table>
</div>
</form>
</body>
</html>
Los estilos y demás archivos requeridos, son los mismos usados en el primer ejemplo (
descargar aquí).

Surge la necesidad cada vez, de enconcontrar la forma de mostrar la información de la base de datos, de manera presentable, dandole al usuario fácil interacción con los registros. Habíamos publicado anteriormente, información sobre el
Flexigrid, un plugin de
JQuery bastante fácil de personalizar.
¿Por qué usar Flexigrid? - es sencillamente fácil de adaptar a tus proyectos ..
- el tamaño de las columnas se puede cambiar en tiempo de desarrollo o ejecución.
- permite filtrar facilmente los campos, pudiendo el programador, agregar nuevos filtros sin mayor complicación.
- permite la paginación de resultados.
- se puede mostrar u ocultar columnas del grid, en tiempo de ejecución o por defecto.
- el estilo es fácil de personalizar.
- permite ajustar el ancho de las columnas.
- permite ordenar los datos por columnas.
- permite conectarse (utilizando
AJAX) a fuente de datos
XML o
JSON.
- permite mostrar u ocultar las columnas.
Veamos un ejemplo de como adaptarlo a
CodeIgniter, a partir del código colgado en
sanderkorvemaker.nl.
A continuación dejo visible sólo el código principal:
Modelo:
grid_m.php
- clic aquí para ver el código
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
xclass Grid_m extends CI_Model {
public function __construct(){
parent::__construct();
$this->load->database('mi_db');
}
function eliminar_registros($items){
if(empty($items)) return false;
// eliminamos espacios en blancos y comas al final de la cadena
$items = rtrim($items,",");
$arrItems = explode(',',$items);
$this->db->where_in('id',$arrItems);// WHERE id IN ($items)
$this->db->delete('country');
return json_encode(array('total'=>$this->db->affected_rows()));
}
function eliminar_todo(){
//$this->db->empty_table('country'); // elimina los registros uno por uno ..
$this->db->truncate('country'); // borra la tabla y la recrea de nuevo
return true;
}
function _get_total($query='',$qtype='',$letter_pressed='Mostrar todo'){
# ----------------------------------------------------------------------
# si se usan las opciones de filtro
if(!empty($qtype) and $letter_pressed<>'Mostrar todo'){
// caso: se esta usando el buscador
if($query!='')
$this->db->like($qtype,$query);// WHERE campo LIKE %valor%
// caso: se filtra por letra
elseif($letter_pressed!='')// WHERE campo LIKE valor%
$this->db->like($qtype,$letter_pressed, 'after');
// caso: se filtra por titulo
elseif($letter_pressed=='#')// WHERE campo REGEXP '[[:digit:]]'
$this->db->where($qtype, " REGEXP '[[:digit:]]' ");
}#----------------------------------------------------------------------
# la opcion (Mostrar todo) por defecto no aplicara filtro
$this->db->from('country');
return $this->db->count_all_results();
}
// devuelve en formato JSON los datos ..
function get_json($query,$qtype,$letter_pressed,$page
,$rp,$sortname,$sortorder){
// obtenemos el total de registros solicitados..
$total = $this->_get_total($query,$qtype,$letter_pressed);
// numero de pagina por defecto 1
$page = (int)(empty($page) ? 1 : $page);
// numero de registros a mostrar, por defecto 10
$rp = (int)(empty($rp) ? 10 : $rp);
// desde donde comenzar
$start = (($page-1) * $rp);
// ordenar por X campo
$sortname = empty($sortname) ? 'name' : $sortname;
// orden ascendente o descendente
$sortorder = empty($sortorder) ? 'desc' : $sortorder;
// armamos la consulta
$this->db->select('id, iso, name, printable_name, iso3, numcode');
$this->db->from('country');
# ----------------------------------------------------------------------
# si se usan las opciones de filtro
if(!empty($qtype) and $letter_pressed<>'Mostrar todo'){
// caso: se esta usando el buscador
if($query!='')
$this->db->like($qtype,$query);// WHERE campo LIKE %valor%
// caso: se filtra por letra
elseif($letter_pressed!='')// WHERE campo LIKE valor%
$this->db->like($qtype,$letter_pressed, 'after');
// caso: se filtra por titulo
elseif($letter_pressed=='#')// WHERE campo REGEXP '[[:digit:]]'
$this->db->where($qtype, " REGEXP '[[:digit:]]' ");
}#----------------------------------------------------------------------
$this->db->limit($rp, $start);
$this->db->order_by($sortname, $sortorder);
$query = $this->db->get();
// echo $this->db->last_query();exit;
// si hay resultados
if ($query->num_rows()>0){
// arrmamos un array con los datos a codificar
$arrDatos = array(
'page' => $page,
'total' => $total
);
foreach($query->result() as $row){
$arrDatos['rows'][] = array(
'id' => htmlspecialchars($row->id,ENT_QUOTES),
'cell' => array(
htmlspecialchars($row->id,ENT_QUOTES),
htmlspecialchars($row->iso,ENT_QUOTES),
htmlspecialchars($row->name,ENT_QUOTES),
htmlspecialchars($row->printable_name,ENT_QUOTES),
htmlspecialchars($row->iso3,ENT_QUOTES),
htmlspecialchars($row->numcode,ENT_QUOTES)
)
);
}#end foreach
$query->free_result();
return json_encode($arrDatos);
}
}
}
?>
Controlador:
grid_c.php
- clic aquí para ver el código
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
xclass Grid_c extends CI_Controller {
public function __construct(){
parent::__construct();
$this->load->model('grid_m','modelo');
}
public function get_json(){
// armamos las condiciones segun sea el caso .. ------------------------
$query = $this->input->post('query');
$qtype = $this->input->post('qtype');
$letter_pressed = $this->input->post('letter_pressed');
$page = $this->input->post('page');
$rp = $this->input->post('rp');
$sortname = $this->input->post('sortname');
$sortorder = $this->input->post('sortorder');
// imprimimos los datos en formato json
echo $this->modelo->get_json($query,$qtype,$letter_pressed,$page
,$rp,$sortname,$sortorder);
}
public function index(){
// indicamos que usaremos el flexgrid
// esto indicara q se incluya la libreria
// y el css del flexgrid solo cuando se necesite
$datos['ShowFlexgrid'] = true;
// cargamos la interfaz
$this->load->view('grid_v', $datos);
}
public function eliminar_registros(){
//echo $this->modelo->eliminar_registros($items);
echo $this->modelo->eliminar_registros($this->input->post('items'));
}
public function eliminar_todo(){
echo $this->modelo->eliminar_todo();
}
}
?>
Vista:
grid_v.php
- clic aquí para ver el código
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="<?php echo base_url(); ?>js/jquery.js"></script>
<?php
if(isset($ShowFlexgrid) and $ShowFlexgrid){
echo '
<link rel="xstylesheet" type="text/css" href="'.base_url().'js/flexigrid/flexigrid.css" />
<script type="text/javascript" src="'.base_url().'js/flexigrid/flexigrid.js"></script>
';
} ?>
</head>
<body>
<!-- establecemos las configuraciones -->
<script type="text/javascript">
$(document).ready(function(){
$("#flex1").flexigrid({
/* indicamos la dirección del archivo que desde el servidor se encarga de
acceder a la base de datos, puede ser un XML o una cadena en formato JSON
devuelta por un archivo PHP, por ejemplo.
*/
url: '<?php echo base_url(),'index.php/grid_c/get_json'; ?>',
// indicamos en que formato se manejaran los datos
dataType: 'json',
/* establecemos una lista de columnas a usar, indicando :
display -> el nombre que vera el usuario
name -> nombre interno de la columna
width -> anchura de la columna
sortable -> si la columna se puede ordenar
align -> la alineación del texto.
*/
colModel : [
{display: 'ID', name : 'id', width : 40, sortable : true, align: 'center'},
{display: 'ISO', name : 'iso', width : 40, sortable : true, align: 'center'},
{display: 'Nombre', name : 'name', width : 190, sortable : true, align: 'center'},
{display: 'Printable', name : 'printable_name', width : 130, sortable : true, align: 'center'},
{display: 'ISO3', name : 'iso3', width : 130, sortable : true, align: 'center', hide: false},
{display: 'Codigo', name : 'numcode', width : 80, sortable : true, align: 'center'}
],
/* agregamos los botones que apareceran en la barra de herramientas
por ejemplo, botones para añadir, editar y eliminar registros.
con la propiedad BClass indicamos el tipo de boton, se establecera asi
la imagen de fondo para el botón
ejemplo: {name: 'Eliminar', bxclass: 'add', onpress : funcion_eliminar}
*/
buttons : [
{name: 'Agregar', bxclass: 'agregar', onpress : test, title:'Agregar nuevo registro'},
{name: 'Editar', bxclass: 'editar', onpress : test, title:'Editar registro'},
{name: 'Eliminar', bxclass: 'eliminar', onpress : test, title:'Eliminar registro(s)'},
{name: 'Eliminar todo', bxclass: 'eliminar_todo', onpress : test, title:'Eliminar todos los registros'},
{name: 'Mostrar todo', bxclass: 'mostrar_todo', onpress : filtro, title:'Mostrar todos los registros'},
/*{separator: true},
{name: '[Mostrar todo]', onpress: filtro},*/
{separator: true}, // linea separadora
{name: 'A', onpress: filtro},
{name: 'B', onpress: filtro},
{name: 'C', onpress: filtro},
{name: 'D', onpress: filtro},
{name: 'E', onpress: filtro},
{name: 'F', onpress: filtro},
{name: 'G', onpress: filtro},
{name: 'H', onpress: filtro},
{name: 'I', onpress: filtro},
{name: 'J', onpress: filtro},
{name: 'K', onpress: filtro},
{name: 'L', onpress: filtro},
{name: 'M', onpress: filtro},
{name: 'N', onpress: filtro},
{name: 'O', onpress: filtro},
{name: 'P', onpress: filtro},
{name: 'Q', onpress: filtro},
{name: 'R', onpress: filtro},
{name: 'S', onpress: filtro},
{name: 'T', onpress: filtro},
{name: 'U', onpress: filtro},
{name: 'V', onpress: filtro},
{name: 'W', onpress: filtro},
{name: 'X', onpress: filtro},
{name: 'Y', onpress: filtro},
{name: 'Z', onpress: filtro},
{separator: true},
{name: '#', onpress: filtro, title:'Buscar por números'}
],
// indicamos que columnas se pueden usar para filtrar las busquedas
searchitems : [
{display: 'ISO', name : 'iso'},
{display: 'Name', name : 'name', isdefault: true}
],
// indicamos el nombre de la columna con la
// q se ordenaran los registros por defecto
sortname: 'id',
// indicamos que por defecto los registros se mostraran ascendentemente
sortorder: "asc",
// esta propiedad permite activar o desactivar los botones de navegación de la página
usepager: true,
// titulo que aparecerá en la ventana
title: 'Lista de Paises',
// indicamos si se permite al usuario especificar el número de resultados por página.
useRp: true,
// numero de registros a mostrar, por defecto 30
rp: 30,
// esta propiedad permite establecer si se puede o no, minimizar la Flexigrid
// (icono en la esquina superior derecha)
showTableToggleBtn: true,
// ancho de la flexigrid por defecto
width: 700,
// alto de la flexigrid por defecto
height: 440
});});
function redireccionar(sControlador){
$(location).attr('href',"<?php echo base_url(); ?>index.php/" + sControlador);
}
// funcion para los botones de filtro
function filtro(com){
jQuery('#flex1').flexOptions({
// indicamos los parametros del filtro
newp:1,
params:[
{name:'letter_pressed', value: com},
{name:'qtype',value:$('select[name=qtype]').val()}
]
});
// recargamos la grid
jQuery("#flex1").flexReload();
}
function test(com, grid){
if (com == 'Agregar'){
redireccionar('add_edit_grid_c/index/ins');
}else if (com == 'Editar'){
if($('.trSelected',grid).length==1){
var items = $('.trSelected',grid);
var itemlist = items[0].id; // id es la primera columna
redireccionar('add_edit_grid_c/index/upd/' + itemlist);
}else if($('.trSelected',grid).length>1){
alert('Sólo puede seleccionar un registro para editar..');
return false;
}else {
alert('Debe seleccionar un registro pata poder actualizarlo..');
return false;
}
}else if (com == 'Eliminar') {
if($('.trSelected',grid).length>0){
if(confirm('Ha seleccionado ' + $('.trSelected',grid).length + ' registro(s) ¿desea eliminarlo(s)?')){
var items = $('.trSelected',grid);
var itemlist = items[0].id;// id es la primera columna
$.ajax({
type: "POST",
dataType: "json",
url: "<?php echo base_url(),'index.php/grid_c/eliminar_registros'; ?>",
data: "items="+itemlist,
success: function(data){
alert("Se ha(n) eliminado un total de " + data.total + " registro(s).");
$("#flex1").flexReload();
}
});
}
} else {
alert('Debe seleccionar un registro pata poder eliminarlo..');
return false;
}
}else if (com == 'Eliminar todo'){
if(confirm('¿Realmente desea eliminar todo los registros de la tabla?')){
$.ajax({
type: "POST",
dataType: "json",
url: '<?php echo base_url(),'index.php/grid_c/eliminar_todo'; ?>',
success: function(data){
alert("Se han eliminado todos los registros de la tabla.");
$("#flex1").flexReload();
}
});
}
}
}
</script>
<table id="flex1" xstyle="display:none;font-size:11px;"></table>
</body>
</html>
Ahí se los dejo..
Enlaces: Web oficial:
flexigrid.infoFramework:
codeigniter.com
Failed to execute SQL. Error: Can\'t update table \'clientes\' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Es el error que le aparece a
Ivan J. Peraza N. al intentar ejecutar el siguiente trigger:
CREATE TRIGGER combinarNombres
AFTER INSERT ON clientes
FOR EACH ROW
BEGIN
UPDATE clientes SET nomClientes = concat(nbrClientes," ",apeClientes);
END$$
(ver cita completa)
Buenos días, le escribo desde Caracas - Venezuela y a continuación le planteo una situación que espero pueda ayudarme. Estoy desarrollando una aplicación para la tesis y tengo una tabla que tiene dos campos nbrClientes (Nombres del Cliente) y apeClientes (Apellidos del Clientes), coloque un campo adicional llamado nomCompleto que quiero sea la combinación de ambos campos, desarrollé un triggers con la intención de que este campo se llene al despues de insertar el registro, el código es el siguiente:
-- Trigger DDL Statements
DELIMITER $$
USE `s2gfra`$$
CREATE
DEFINER=`root`@`localhost`
TRIGGER `s2gfra`.`combinarNombres`
AFTER INSERT ON `s2gfra`.`clientes`
FOR EACH ROW
BEGIN
UPDATE `clientes` SET `nomClientes` = concat(`nbrClientes`,\", \",`apeClientes`);
END$$
Pero cuando desde la aplicación se crea el registro me arroja el siguiente error:
Failed to execute SQL. Error: Can\'t update table \'clientes\' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Llevo un par de días intentando solucionar esta situación pero no lo he logrado. Espero que pueda darme luz para resolverlo, de antemano, muchas gracias por su tiempo.
Veamos lo que dice la
documentación de MySQL:
- Las columnas de la tabla asociada con el disparador pueden referenciarse empleando los alias OLD y NEW.
- El uso de SET NEW.nombre_col = valor necesita que se tenga el privilegio UPDATE sobre la columna.
ejemplo: teniendo la siguiente tabla, crear un disarador que actualice el campo
nombre_completo con el resultado de la
concatenación del
nombre y el
apellido introducido..
CREATE TABLE clientes
(
id_cliente INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(20) NOT NULL,
apellido VARCHAR(20) NOT NULL,
nombre_completo VARCHAR(42)
);
En lugar de usar la tipica sentencia
UPDATE .. seteamos el campo directamente:
SET NEW.nombre_completo = CONCAT(NEW.nombre,' ',NEW.apellido);
DROP TRIGGER IF EXISTS upd_nombre_completo;
DELIMITER $$
CREATE TRIGGER upd_nombre_completo BEFORE INSERT ON clientes
FOR EACH ROW
BEGIN
SET NEW.nombre_completo = CONCAT(NEW.nombre,' ',NEW.apellido);
END$$
DELIMITER ;
y al hacer la inserción y la consulta, obtenemos:
mysql> INSERT INTO clientes (nombre,apellido) VALUES ('Ana','Arjona');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM clientes;
+------------+--------+----------+-----------------+
| id_cliente | nombre | apellido | nombre_completo |
+------------+--------+----------+-----------------+
| 1 | Ana | Arjona | Ana Arjona |
+------------+--------+----------+-----------------+
1 row in set (0.00 sec)
Lo dejo aquí para quien le pueda servir y como complemento al post
triggers en MySQL.

Hace un tiempo publique un ejemplo de
estilo para un sistema de comentarios que tenía en mente para matar el tiempo, el cual sería desarrollado usando
XAJAX y
MySQL como principales tecnologías, nada de otro mundo, en su momento no lo seguí por diversas razones.
Recientemente,
JRT comentó "
soy nuevo en el mundo de ajax y me gustaría saber si podrías poner un ejemplo de como hacer la conexión a la base de datos que no se como colocarla", así que con un poco de tiempo libre, le armo una respuesta.
Con algunas modificaciones a los archivos del
post base, conseguiremos algo así:
Para el ejemplo usare una sola tabla llamada
comentarios, la cual, debería tener una tabla padre llamada
temas, ya que un topic puede tener varias respuestas, pero como no me intersa más que mostrar la interacción con una sola tabla, solo usaremos la primera nombrada.
CREATE DATABASE db_xajax CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE TABLE comentarios
(
id_comentario integer auto_increment primary key,
nombre varchar(20) not null,
email varchar(100) not null,
web varchar(100) default '',
comentario text not null
) ENGINE=INNODB;
Nuestro
index.php queda así:
Clic aquí para mostrar/ocultar el código
<?php
// incluimos la clase
require_once("xajax/xajax_core/xajax.inc.php");
// incluimos las funciones generales
require_once("mod_ppal.php");
// creamos una instancia al objeto XAJAX:
$xajax = new xajax();
// valida el campo pasado por parametro
function form_manage($form,$sCampo){
// obtenemos el valor del campo
$sValorCampo = trim($form["txt_$sCampo"]);
$sMsj = '';//inicializamos
// iniciamos las validaciones ***
if (empty($sValorCampo))// si el campo está vacio
$sMsj = ' éste campo es obligatorio.';
elseif ($sCampo == 'nombre' or $sCampo == 'comentarios')
$sMsj = no_es_valida_cadena($sValorCampo,$sCampo);
elseif ($sCampo == 'email')
$sMsj = no_es_email_valido($sValorCampo);
// asignamos el valor que determinara la imagen
// y el mensaje a mostrar por campo
$sImg = ($sMsj===false ? 'correcto' : 'incorrecto');
// asignamos el mensaje por campo..
$sHTMLMsj = "<img border='0' src='imagenes/$sImg.png' />"
.($sImg == 'incorrecto' ? $sMsj : '');
// creamos una nueva instancia para generar
// la respuesta con ajax (xajaxResponse).
$objRespuesta = new xajaxResponse();
// mostraremos la cantidad de caracteres del txt_comentarios
if(!empty($form['txt_comentarios']))
$objRespuesta->assign('total_caracteres','innerHTML'
,strlen(trim($form['txt_comentarios'])));
else
$objRespuesta->assign('total_caracteres','innerHTML', '0');
//---------------------------------------------------------------------------
// actualizamos los div
$objRespuesta->assign("error_$sCampo",'innerHTML', $sHTMLMsj);
// retornamos el objeto
return $objRespuesta;
}
function form_process($form){
// creamos una nueva instancia para generar la respuesta con ajax
$objRespuesta = new xajaxResponse();
// si los campos no estan correctos
if (no_es_valida_cadena($form['txt_nombre'],'nombre') or
no_es_email_valido($form['txt_email']) or
no_es_valida_cadena($form['txt_comentarios'],'comentarios')){
$objRespuesta->alert('¡El formulario debe estar perfectamente validado!');
}else{
if (ms_insert($form['txt_nombre'],$form['txt_email']
,$form['txt_web'],$form['txt_comentarios'])){
//
$objRespuesta->alert('¡tu comentario ha sido agregado!');
$objRespuesta->redirect('index.php');
}else
$objRespuesta->alert('¡el comentario no pudo ser agregado!');
// limpiamos los campos -------------------------------------
$ArrayCampos = array('nombre','email','web','comentarios');
foreach($ArrayCampos as $sValor){
$objRespuesta
->clear("txt_$sValor",'value')
->clear("error_$sValor",'innerHTML');
}
}
return $objRespuesta;
}
function html_comentarios(){
$arrComentarios = ms_query();
if(is_array($arrComentarios)){
$c=1;
foreach($arrComentarios as $arrComentario){
// $arrComentario[0] => nombre
// $arrComentario[1] => comentario
echo '<div id="comment_box"><div xclass="numero">'.$c++
.'</div><div xclass="avatar_default"></div>
<div xclass="autor"><b>'.$arrComentario[0]
.'</b> dijo ..</div>
<div xclass="contenido">'.$arrComentario[1]
.'</div></div>';
}
}else
echo '<div xclass="highlight">No se encontraron comentarios..</div>';
}
$xajax->registerFunction('form_manage'); // gestiona las validaciones del formulario
$xajax->registerFunction('form_process'); // procesa los datos del formulario
// le indicamos al objeto xajax que procese la peticion / el pedido
$xajax -> processRequest();
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link href="css/estilo.css" rel="xstylesheet" />
<title>XAJAX-MySQL: mini sistema de comentarios</title>
<?php
//se le dice que incluya el JavaScript generado desde XAJAX
$xajax->printJavascript('xajax/');
?>
</head>
<body>
<div id='main'>
<div id="tablon"><?php echo html_comentarios(); ?></div>
<div id='clear'></div>
<div id="comment_area">
<h3>Deja un comentario</h3>
<p xclass='nota'>Tu Email NO será publicado. Los campos marcados con asteriscos
(<span xclass="requerido">*</span>) son obligatoríos.</p>
<form action='javascript:void(null);' method="post"
id="form_comment" name="form_comment"
onsubmit="xajax_form_process(xajax.getFormValues('form_comment'))">
<p xclass='campo'>Nombre: <span xclass="requerido">*</span>
<input tabindex='1' id="txt_nombre" name="txt_nombre" size="29"
type="text" maxlenght="20"
onkeyup="xajax_form_manage(xajax.getFormValues('form_comment'),'nombre')"
onblur="xajax_form_manage(xajax.getFormValues('form_comment'),'nombre')" />
<span xclass="error" id='error_nombre'></span>
</p>
<p xclass='campo'>Email: <span xclass="requerido">*</span>
<input tabindex='2' id="txt_email" name="txt_email" size="30"
type="text" value='@' maxlenght="100"
onkeyup="xajax_form_manage(xajax.getFormValues('form_comment'),'email')"
onblur="xajax_form_manage(xajax.getFormValues('form_comment'),'email')" />
<span xclass="error" id="error_email"></span>
</p>
<p xclass='campo'>Web:
<input tabindex='3' id="txt_web" name="txt_web"
value="http://" size="32" maxlenght="100" type="text" />
</p>
<p xclass='campo'>Comentario: <span xclass="requerido">*</span>
<span xclass="error" id="error_comentarios"></span></p>
<p xclass='campo'>
<textarea tabindex='4' xclass='estilotextarea' id="txt_comentarios"
name="txt_comentarios"
onkeyup="xajax_form_manage(xajax.getFormValues('form_comment'),'comentarios')"
onblur="xajax_form_manage(xajax.getFormValues('form_comment'),'comentarios')" />
</textarea>
<span xclass="total_caracteres" id="total_caracteres">0</span>
</p>
<p xclass='submit'>
<input tabindex='5' name="submit" id="submit"
value="Publicar comentario" type="submit" />
</p>
</form>
</div>
</div>
</body>
</html>
y nuestro
mod_ppal.php queda así:
Clic aquí para mostrar/ocultar el código
<?php
function ms_connect(){
$conex = @mysql_connect('localhost','tu_usuario','tu_pass');
//obviamente no colocaras contraseña si tu usuario de MySQl no la requiere..
if(is_resource($conex)){
if(!@mysql_select_db('db_xajax'))
die('Error: no se puede seleccionar la base de datos.');
else
return $conex;
}else
die('Error: no se puede conectar con la base de datos.');
}
function ms_insert($sNombre,$sEmail,$sWeb,$sComentario){
if(empty($sNombre) or empty($sEmail)
or empty($sComentario)) return false;
$conex = ms_connect();
$sSQL = "INSERT INTO comentarios ";
$sSQL .= "(nombre,email,web,comentario) VALUES ('";
$sSQL .= mysql_real_escape_string(trim($sNombre))."','";
$sSQL .= mysql_real_escape_string(trim($sEmail))."','";
$sSQL .= mysql_real_escape_string(trim($sWeb))."','";
$sSQL .= mysql_real_escape_string(trim($sComentario))."');";
//exit($sSQL);
mysql_query($sSQL,$conex);
$id = mysql_insert_id($conex);
ms_close($conex);
return $id ? $id : false;
}
function ms_query(){
$sSQL = 'SELECT nombre,comentario FROM comentarios';
$conex = ms_connect();
$result = mysql_query($sSQL,$conex);
if(is_resource($result) and mysql_num_rows($result)>0){
$data = array();
while ($row = mysql_fetch_array($result, MYSQL_NUM)){
$data[] = get_array_filter($row);
}
mysql_free_result($result);
ms_close($conex);
return $data;
}else
return false;
}
function ms_close($conex){
if(is_resource($conex)) mysql_close($conex);
}
// filtra el contenido a mostrar
function get_array_filter($quien){
if(is_array($quien)){
foreach($quien as $id => $sValor){
$quien[$id] = get_array_filter($sValor);
}
return $quien;
}else
return htmlspecialchars($quien, ENT_QUOTES);
}
// valida Email
function no_es_email_valido($sEmail){
if(empty($sEmail)) return true;
// primero validamos la longuitud
if ((strlen($sEmail) < 6) or (strlen($sEmail) > 100))
return 'Error: debe tener entre 6 y 100 caracteres.';
else{
$patron="/^[_a-zA-Z0-9-ñÑ]+(\\.[_a-zA-Z0-9-ñÑ]+)*@+([_a-zA-Z0-9-
]+\\.)*[a-zA-Z0-9-]{2,100}\\.[a-zA-Z]{2,6}$/";
return (!preg_match($patron,$sEmail)
? 'Error: email incorrecto' : false);
}
}
// validara los campos "nombre y comentarios"
function no_es_valida_cadena($sCadena,$sCampo){
if(empty($sCadena) or empty($sCampo)) return true;
if (!es_correcta_cadena($sCadena))
return 'Error: solo caracteres alfanumericos, espacios, apóstrofe.';
else{
$min = $sCampo == 'comentarios' ? 5 : 3;
$max = $sCampo == 'comentarios' ? 512 : 20;
if ((strlen($sCadena) < $min) or (strlen($sCadena) > $max))
return "Error: debe tener entre $min y $max caracteres.";
else
return false;
}
}
// se compara el campo de confirmacion
function es_correcta_cadena($sCadena){
if(empty($sCadena)) return false;
return preg_match("/^[0-9a-z_ÑÁÉÍÓÚÄËÏÖÜñáéíóüäëïöü.,\'\s]*$/i",$sCadena);
}
?>

Involucrada: multifuncional Epson Tx300.
Caso: el papel se atascó y como consecuencia mostraba el mensaje "
Error de impresora", el problema se presenta cuando retiran el papel que se atasca sin apagar la impresora, el error no deja de aparecer a pesar de haber retirado la hoja atascada, incluso si apagas la impresora y la enciendes de nuevo.
Solución:Como la impresora no detecta que el papel ha sido retirado, hay que generar manualmente un error que sea fácil de solucionar, y que en el orden, sea más importante que el papel atascado, puede ser "ausencia de cartuchos".
1.- apagamos la impresora y desconectamos el cable de corriente.
2.- retiramos todos los cartuchos de la impresora.
3.- asegúrate de que realmente no hay papel atascado, retira las hojas.
3.- esperamos mínimo 10 minutos.
4.- conectamos el cable de corriente y encendemos la impresora, debería mostrar un nuevo error "no se detectan los cartuchos".
5.- con la impresora encendida, colocamos los cartuchos como deben ir y presionamos "ok".
6.- la impresora debería cargar la nueva configuración anulando los dos errores.
7.- imprime una hoja de prueba y listo, debería haberse solucionado el problema.
