lunes, 24 de abril de 2017

PHP Warning: Creating default object from empty value in nusoap/lib/nusoap.php on line 75

Utilizando el NuSoap 0.9.5 encontré que el log de errores del apache se comenzó a llenar de mensajes “PHP Warning: Creating default object from empty value in nusoap/lib/nusoap.php on line 75”. Busqué la solución al problema en la web y no encontré ninguna solución que no fuera bloquear la presentación del log.

Al ver que el objeto $GLOBALS al cual se le asigna el valor 9 no existía y el servidor lo debía crear por defecto.

$GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;

Pensé que sería mejor crearlo siempre que no exista. Por esto agregué las siguentes líneas.

if(isset($GLOBALS['_transient'])){
$GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
}else{
$GLOBALS['_transient']['static']['nusoap_base'] = new stdClass();
$GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
}


Después de esta modificación el log dejo de escribir el Warning y se solucionó el problema.

"Gracias, por compartir tus conocimientos"

jueves, 24 de marzo de 2016

Join en Tablas con PostgreSQL


Existen dos tipos de combinaciones

Combinaciones internas de tablas: Donde cada registro de la tabla A se combina con otro de la tabla B que cumpla las condiciones.

Inner Join
       
    select * from empleado as a, departamento as b where a.departamento_id = b.id;

    select * from empleado as a inner join departamento as b on a.departamento_id = b.id;
    select * from empleado as a join departamento as b on a.departamento_id = b.id;
Para PostgreSQL utilizar inner join o join se refiere a la misma instrucción, en ambos casos se hacer referencia a una unión interna donde cada uno de los registros debe quedar asociado a un registros de la otra tabla.

En lugar de utilizar ON también se puede utilizar USING para especificar el campo con el cual se desea realizar la igualdad cuando los nombre de los campos son iguales en ambas tablas.


    select * from departamento join oficina using (id);
    select * from departamento join oficina using (nombre);

En ambos casos se obtendrán diferentes resultados según los valores almacenados en cada tabla.

Usign también permite realizar la búsqueda por más de un campo, cuando más de un campo de la tabla tiene el mismo nombre.


    select * from departamento join oficina using (id, nombre);

Natural Join


    select * from departamento natural join oficina;

Cuando tenemos el mismo nombre de campo para diferentes tablas, podemos usar el o los campos con el mismo nombre para unir diferentes tablas. Esta unión es un tipo especial de inner join. Esta operación iguala todas las columnas que tienen el mismo nombre en ambas tablas presentando como resultados solo los registros que tienen correspondencia.

Combinaciones externas de tablas: Donde se recuperan todos los registros de una tabla tengan o no correspondencia en la otra tabla.

Outer Join por la Izquierda


    select * from empleado as a left join departamento as b on a.departamento_id = b.id; 
    select * from empleado as e left outer join departamento as d on e.departamento_id = d.id;

Esta consulta recuperará todos los registros de la tabla izquierda (empleado) tengan o no correspondencia en la tabla derecha (departamento).

Outer Join por la Derecha


    select * from empleado as a right join departamento as b on a.departamento_id = b.id; 
    select * from empleado as e right outer join departamento as d on e.departamento_id = d.id;

Esta consulta recuperará todos los registros de la tabla derecha (departamento) tengan o no correspondencia en la tabla izquierda (empleado).

Outer Join Full


    select * from empleado as e full join departamento as d on e.departamento_id = d.id;
    select * from empleado as a full outer join departamento as b on e.departamento_id = b.id;
Esta consulta recuperará todos los registros de la tabla derecha (departamento) e izquierda (empleado) tengan o no correspondencia en la tabla izquierda (empleado) y derecha (departamento) respectivamente.

En los tres casos anteriores los registros que no tengan correspondencia completarán los campos con el valor null.

Cross Join
 

    select * from empleado, departamento; 
    select * from empleado cross join departamento;

La más simple unión, es una unión de cruce, esto crea un conjunto resultado de todas las posibles combinaciones de las filas entre ambas tablas.

Existen otros tipos de combinaciones que corresponden a modificaciones de las consultas anteriores, pero que pueden ser de gran ayuda en algunos caso particulares.
 

    select * from empleado as e left join departamento as d on e.departamento_id = d.id
where d.id is null;

Esta consulta presenta todos los registros de la tabla izquierda (empleado) que no se encuentran asociados a los registros de la tabla derecha (departamento). 

    select * from empleado as e right join departamento as d on e.departamento_id = d.id
where e.id is null;

Esta consulta presenta todos los registros de la tabla derecha (departamento) que no se encuentran asociadas a los registros de la tabla izquierda (empleado).

    select * from empleado as e full join departamento as d on e.departamento_id = d.id
where e.id is null or d.id is null;

Esta consulta presenta todos los registros de la tabla izquierda (empleado) y de la tabla derecha (departamento) que no se encuentran asociados a la otra tabla.


Referecias:

https://www.imaginanet.com/blog/diferencias-entre-join-left-join-y-right-join.html
http://donnierock.com/2014/03/04/diferencia-entre-inner-join-left-join-y-right-join-sql/
http://www.postgresqlforbeginners.com/2010/11/sql-inner-cross-and-self-joins.html

"Gracias, por compartir tus conocimientos"

martes, 3 de noviembre de 2015

Warning al Crear un WebService con NuSoap en PHP

Al crear un webservice para que responda a peticiones de un cliente utilizando la librería nusoap, se genera un Warning en el log de errores del Apache como se puede observar en la siguiente línea.

[Mon Nov 02 12:10:39 2015] [error] [client 192.168.xxx.xxx] PHP Warning:  get_class() expects parameter 1 to be object, string given in /xxx/xxx/nusoap/lib/nusoap.php on line 4022

Este Warning es generado en el archivo nusoap.php ubicado en ./nusoap/lib/nusoap.php y se puede solucionar remplazando la línea 4022 que originalmente esta escrita como se puede observar en la siguiente línea.

if (isset($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {

Por una línea que fuerce la variable $this-methodreturn a un objeto, de manera que se pueda utilizar la función get_class() sin problemas, obteniendo como resultado la siguiente línea.

if (isset($this->methodreturn) && ((get_class((object)$this->methodreturn) == 'soap_fault') || (get_class((object)$this->methodreturn) == 'nusoap_fault'))) {


La función get_class() de PHP debe recibir como parámetro un object y la variable $this->methodreturn no podemos asegurar que sea un object, por lo tanto, se debe forzar la variable para convertirla en el tipo de variable.

Referencia:
http://forums.devshed.com/php-development-5/nusoap-simple-example-681714.html

http://php.net/manual/es/function.get-class.php

"Gracias, por compartir tus conocimientos"

viernes, 15 de mayo de 2015

Ajax: Uploader un Archivo con AJAX sin Jquery

Almacenar un archivo a través de una pagina Web utilizando los formularios de HTML es bastante común, sin embargo realizar esta operación utilizando AJAX sin JQuery fue un poco más difícil encontrar la información de como se realizaba esta operación.

Lo primero que se debe realizar es crear un formulario con HTML que contenga solo el campo de tipo file que se utilizará para enviar el archivo, si en este formulario se agregan más campos estos pasarán junto con el archivo y luego habrá que limpiar el archivo para poder almacenarlo como corresponde. Si necesitas almacenar recibir más campos en el formulario puedes crear dos formularios, primero pasas el archivo a través de la función Ajax y una vez que eso termino correctamente puedes pasar el resto de los campos a través de otra función Ajax.

A continuación se presenta el código de un formulario HTML que permite recuperar el archivo desde una pagina web.

<form id="frm_subir_archivo" name="frm_subir_archivo" method="POST" enctype="multipart/form-data" accept-charset="utf-8">
<input type='file' id='fle_archivo>' name='fle_archivo' />
</form>
<br />
<input id='btn_guardar' type='button' value='Guardar' onClick='cargarArchivo();' />


Al observar se puede ver que el botón Guardar no está dentro del formulario, porque como se mencionó anteriormente, si estuviera incluido en el formulario el archivo contendría algunas lineas que representarían el valor que tiene el botón dentro del formulario.

Una vez que existe el formulario se debe crear la función encargada de recuperar el archivo y enviarlo al Servidor que lo tiene que almacenar. En este caso la función se llama cargarArchivo() y es llamada una vez que se presiona el botón Guardar.

A continuación se presenta el código de la función JavaScript que utiliza el ajax que envía el archivo al Servidor.

function cargarArchivo(){
    var archivo = $('#fle_archivo').val().trim();

    if(archivo == ""){
        alert('Debe seleccionar un archivo');
        return false;
    }

    //obtenemos un array con los datos del archivo
    archivo = $("#fle_archivo")[0].files[0];
    //obtenemos el nombre del archivo
    var archivo_nombre = archivo.name;
    //obtenemos la extensión del archivo
    var archivo_extension = archivo_nombre.substring(archivo_nombre.lastIndexOf('.') + 1);
    //obtenemos el tamaño del archivo
    var archivo_tamano = archivo.size;
    //obtenemos el tipo de archivo image/png ejemplo
    var archivo_tipo = archivo.type;

    var objeto = objetoAjax();
    //objeto.open("POST", "ajax.php", true);
    objeto.open("PUT", "ajax.php", true);
    objeto.onreadystatechange = function() {
        if (objeto.readyState === 0) {
            div_msg.html('<img src'+'='+'"./ajax-loader.gif"/> Preparando datos...');
        } else if (objeto.readyState === 1) {
            div_msg.html('<img src'+'='+'"./ajax-loader.gif"/> Procesando consulta...');
        } else if (objeto.readyState === 2) {
            div_msg.html('<img src'+'='+'"./ajax-loader.gif"/> Esperando respuesta...');
        } else if (objeto.readyState === 3) {
            div_msg.html('<img src'+'='+'"./ajax-loader.gif"/> Recibiendo respuesta...');
        } else if (objeto.readyState === 4) {
            var response = objeto.responseText.tratarResponseText();
            var estado = response.substring(0, 2);
            response = response.substring(2);
            if(estado == 'OK'){
                alert(response);
            }else if(estado == 'FL'){
                alert(response);
            }else if(estado == 'WN'){
                alert(response);
            }else if(estado == 'AL'){
                alert(response);
            }else{
            }
        }
    };
    //objeto.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    objeto.setRequestHeader("Content-Type", "multipart/form-data");
    objeto.setRequestHeader("Content-length", file_size);
    objeto.setRequestHeader("X_FILENAME", file_name);
    var variables = archivo;
    objeto.send(variables);
}


Es necesario aclarar que el código utiliza Jquery para obtener el valor de los campos, pero no lo utiliza para realizar el envío de datos a través de Ajax.

Lo primero es verificar que el campo que contiene el archivo no venga vació, si está vacío se envía una alerta explicando el error y se de tiene el script. Si el campo es distinto de vacío se obtienen los diferentes valores que entrega un campo de tipo archivo, como son el nombre, la extensión, el tamaño y el tipo de archivo, sin olvidar la variable archivo que contiene el cuerpo del archivo.

Después se crea el objetoAjax, se abre la conexión con el servidor y se indica de que modo se enviarán los datos. Los métodos típicos para enviar datos desde un formulario HTML a un servidor son GET y POST, pero para este caso se utiliza PUT que se utiliza para almacenar archivos en un servidor.

Después se obtienen los diferentes cambios de estado de la conexión Ajax hasta llegar al estado 4 en el momento que el Script Ajax retorna la respuesta de la solicitud. El string de respuesta lo dividimos en los dos primeros caracteres que indican la condición de retorno OK (operación exitosa), FL (operación fallo), WN (peligro en la operación), AL (alerta en la operación) y se envía una alerta con una descripción de la respuesta.

Se agrega un header indicando el tipo de formulario que se envía al servidor, el tamaño del archivo y el nombre del archivo, para ser recibidos en el servidor, por último se envían los argumentos hacia el servidor, en este caso el archivo adjunto.

En la función cargarArchivo() se utiliza la función objetoAjax para crear un objeto que sea capaz de enviar la información obtenida al Servidor y la función tratarResponseText que permite recuperar la respuesta entregada por el servidor a la petición realizada desde el JavaScript. Ambas funciones se presentan en el siguiente código fuente.

// JavaScript Document  Objeto Ajax
String.prototype.tratarResponseText=function(){
    var pat=/<script[^>]*>([\S\s]*?)<\/script[^>]*>/ig;
    var pat2=/\b\s+src=[^>\s]+\b/g;
    var elementos = this.match(pat) || [];
    for(i=0;i<elementos.length;i++) {
        var nuevoScript = document.createElement('script');
        nuevoScript.type = 'text/javascript';
        var tienesrc=elementos[i].match(pat2) || [];
        if(tienesrc.length){
            nuevoScript.src=tienesrc[0].split("'").join('').split('"').join('').split('src=').join('').split(' ').join('');
        }else{
            var elemento = elementos[i].replace(pat,'$1');
            nuevoScript.text = elemento;
        }
        document.getElementsByTagName('body')[0].appendChild(nuevoScript);
    }
    return this.replace(pat,'');
}

function objetoAjax(){
    var xmlhttp=false;
    try {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
        try {
           xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (E) {
            xmlhttp = false;
        }
    }

    if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
        xmlhttp = new XMLHttpRequest();
    }
    return xmlhttp;
}


Ahora que se ha explicado todos los códigos desde el lado del cliente, se puede ver como se recupera el archivo en el servidor. El código para recuperar el archivo y almacenar el archivo se presenta a continuación.

if (isset($_SERVER['HTTP_X_FILENAME'])) {
    $archivo_nombre = $_SERVER['HTTP_X_FILENAME'];
    $archivo_nombre = date('YmdHis')."_".$archivo_nombre;
    file_put_contents(
        '/tmp/'.$archivo_nombre,
        file_get_contents('php://input')
    );
    echo 'OK'.$archivo_nombre;
}else{
    echo 'FLEl archivo no fue almacenado.';
}


Se pregunta si existe el nombre del archivo, de no ser así se devuelve un error indicando que el archivo no fue almacenado. Si existe el nombre de archivo se recupera en una variable a la cual se agrega la fecha para que no se borren los archivos subidos con el mismo nombre, después se recupera el contenido del archivo y se pasa a una string con la función file_get_contents(). Con la función file_put_contents que escribe el contenido de un string a un archivo ubicado en la dirección indicada como primer parámetro.

Con estos códigos se puede recuperar un archivo desde la interfaz web del cliente y enviar a un servidor a través de Ajax, sin utilizar Jquery para enviar este archivo.

Referencia:

http://uno-de-piera.com/subir-imagenes-con-php-y-jquery/
http://www.eduardocasas.com/es/blog/10-11-2012/xmlhttprequest-2-subiendo-archivos-al-servidor-por-medio-de-ajax
http://aprende-web.net/progra/ajax/ajax_11.php
https://github.com/FineUploader/fine-uploader/issues/61

"Gracias, por compartir tus conocimientos"

martes, 3 de marzo de 2015

CSS: SPAN con ancho fijo

El validador W3C de HTML muestra como error agregar un <div> dentro del elemento <td> de una tabla, sin embargo, al agregar un elemento <span> dentro del elemento <td> de una tabla no presenta ningún inconveniente para el validador. Esto provocó que en algunos segmentos de mis archivos HTML prefiera utilizar etiquetas <span> en lugar de <div>, pero me encontré con un problema al definir el ancho de un elemento <span>, esto me llevo a encontrar la siguiente solución en Internet.

Las etiquetas HTML tiene por omisión una disposición en bloque (block) o en línea (inline). Algunos ejemplos de elementos dispuestos en bloque <div>, <p>, <h1>, <form> y <li>; mientras que los que se muestran en línea pueden ser <span>, <a>, <label>, <strong>, <b> y <em>. Una de las características de los elementos div y span es que se le puede cambiar el ancho (width).

span { width: 100px; }

En teoría, esto hace que la caja que genera el <span> tenga 100 pixels de largo, pero lamentablemente en los navegadores el <span> sólo tendrá el largo de los caracteres que aloje. Para solucionar este problema se puede utilizar el siguiente estilo:

span {
width: 100px;
display:block;
}

Esto hace que el <span> se convierta en un elemento en bloque, pero también causará que el siguiente elemento en línea salte a la línea siguiente. Para evitar esto se puede agregar float:left al css.

Referencias:

http://web-ar.blogspot.com/2007/01/css-span-con-ancho-fijo.html


"Gracias, por compartir tus conocimientos"

martes, 27 de enero de 2015

Linux: Eliminar directorios .svn de todos los subdirectorios


En varias ocasiones he instalado el controlador de versiones Subversion (SVN), el cual es muy útil para trabajar en equipo sin dañar las modificaciones que otro miembro del equipo ha realizado al sistema. Este sistema crea un directorio oculto en cada uno de los subdirectorios del proyecto en que fue instalado y en algunos momentos es necesario eliminar estos directorios.

Eliminar cada uno de estos directorios no es mayor problema cuando el proyecto tiene solo un directorio, pero cuando el proyecto tiene muchos directorios y además utiliza framework que contienen muchos directorios anidados, la tarea puede ser interminable.

Una buena solución es utilizar la propiedad de ejecutar comandos con find en Linux.

find . -name “.svn” -type d -exec rm -rf {} \;

ó

find . -name .svn -exec /bin/rm -fR '{}' \;

Para entender un poco mejor el funcionamiento de estos comandos se describe que acción realiza cada uno de ellos.

  • find: comando de Linux utilizado para buscara archivos en directorios jerárquicos.
  • .: indica que la búsqueda debe comenzar en el directorio actual y seguir con los subdirectorios que el directorio actual contiene.
  • -name nombre_archivo: indica que se debe realizar la búsqueda de los archivos que coinciden con el nombre_archivo ingresado o con parte de ese nombre. Al no utilizar caracteres comodines como *, ? o [], el comando buscará un nombre de archivo que coincida completamente con el nombre ingresado, si utiliza caracteres comodines se buscarán los archivos que coincidan con la expresión regular generada por el nombre de los archivos más los comodines. Para utilizar comodines el nombre del archivo debe ir entre comillas dobles “.
  • -type tipo_archivo: indica el tipo de archivo que se está buscando, los tipos son:
    • b: bloque especial (buffered)
    • c: carácter especial (unbuffered)
    • d: directorio
    • p: tubería con nombre (FIFO)
    • f: archivo regular
    • l: link simbólico. Este nunca es verdadero si la opción -L o la opción -follow están en efecto, amenos que se rompa el link simbólico. Si tu deseas buscar link simbólicos cuando -L está en efecto, usa -xtype.
    • s: socket
    • D: puerta (Solaris)
  • -exec comando: Ejecuta un comando.. Es verdadero si el estado retornado es 0. Todos los argumentos siguientes a find son tomados para ser argumentos del comando hasta un argumento que consiste en ; se encuentre. La cadena '{}' es remplazada por el nombre del archivo actual siendo procesado en todas partes donde se encuentre en el argumento para el comando, no solo en argumentos donde esta solo, como en algunas versiones de find. Ambas de estas construcciones pueden ser escapadas (con un '\') o citado para protegerlos de la expansión por la shell. El comando especificado esta corriendo una vez por cada archivo encontrado. El comando es ejecutado en el comienzo del directorio. Hay inevitables problemas de seguridad circundantes al uso de la acción -exec; tu deberías usar la opción -execdir en su lugar.

lunes, 23 de diciembre de 2013

PHP: Diferencias y Similitudes entre Require e Include


Al realizar desarrollos en PHP es común encontrarse con las funciones require() e include(), estas funciones permite agregar en el script donde se insertan todo el contenido de otro script.
Estas funciones son muy útiles para agregar archivos con funciones comunes a varios scripts o para permitir que el código quede más ordenado. Por ejemplo, se crea una función para verificar si un RUT es válido y esta función se utiliza en diez script diferentes, en lugar de escribir 10 funciones, se puede crear un script que contenga la función y luego se agrega el archivo en los script donde se van a utilizar.

Script con la función valida_rut.

valida_rut.php

<?php
function valida_rut($in_rut){
.
.
.
}
?>

Utilización de la función require().

utiliza_valida_rut.php

<?php
require(“ruta/valida_rut.php”);
$rut = '13478217-2';
valida_rut($rut);
?>

Utilización de la función include().

utiliza_valida_rut.php

<?php
include(“ruta/valida_rut.php”);
$rut = '13478217-2';
valida_rut($rut);
?>

Estas dos funciones parecieran hacer lo mismo, pero tienen una importante diferencia, como lo dice su nombre la primera función (require) requiere que el archivo exista para agregar el archivo, si el archivo no existe el código presentará un error “PHP Fatal error” y la ejecución del código se detendrá. La segunda función (include) incluye el archivo, pero si este archivo no existe enviará un error de tipo “Warning” lo cual permitirá que el código se siga ejecutando.

Cuando se utiliza la función require() o include(), es como si ambos script quedarán convertidos en uno solo, por lo tanto el script padre (quien utiliza la función require o include) y script hijo (quien es insertado a través de la función require(“archivo.php”) o include(“archivo.php”)) tienen acceso a cualquier función que este en cualquiera de los dos archivos, así como a las funciones que existan en otros script que han sido agregados tanto en el padre como en el hijo a través de la función require o include. Esto puede presentar inconvenientes, por ejemplo si tanto el padre como el hijo agregan un script llamada repetido.php, todo el código contenido en repetido.php quedará duplicado, lo cual puede acarrear problemas de variables duplicadas o funciones duplicadas, por este motivo se debe tener especial cuidado en la utilización de estas funciones. Para evitar este tipo de problemas yo evito que los archivos hijos utilicen las funciones require e include, pero si las agregas con cuidado, verificando que un archivo padre y uno hijo no contengan los mismos script no existe ningún problema.

Una opción para evitar el problema de agregar dos veces el mismo script es utilizar las funciones require_once o include_once. Estas funciones trabajan igual que las anteriores con la única diferencia que evalúan si el archivo ha sido agregado anteriormente y si este es el caso no lo vuelen a incluir, sin embargo estas funciones son más pesadas y consumen más recursos lo que implica que deben ser utilizadas solo cuando sea necesario.

Otro punto que se debe tener en cuenta a la hora de utilizar las funciones require e include es la utilización de variables de sesión. Cuando se inicia una sesión que previamente estaba iniciada se presenta un error de tipo “Notice”, es posible que al utilizar require o include se inicie una sesión en el archivo padre y luego en el archivo hijo, lo cual provocará el error antes mencionado. Con un error de tipo “Notice” se puede continuar con la ejecución del código, pero es importante mencionar que esto puede hacer más tediosa la búsqueda de errores del sistema, porque el log de errores crece mucho más por este tipo de errores ocultando los errores más graves que pueden perjudicar la correcta ejecución del sistema.

Referencias:
"Gracias, por compartir tus conocimientos"

jueves, 7 de noviembre de 2013

Linux: Copiar contenido de un directorio, excluyendo algunos archivos


Uno de los comandos más utilizados en la consola de Linux es cp que nos permite copiar un archivo o directorio en otra ubicación. Al tratar de copiar el contenido de un directorio, necesitaba dejar fuera de esta copia varios archivos que por su tamaño no podían ser copiados a la nueva ubicación, después de investigar en la web encontré el modo de realizar esta operación utilizando el comando cp. A continuación se detallan el modo de realizar esta operación.

cp directorio_o/!(archivo.txt) directorio_d: copia todos los archivos que están en el directorio directorio_o menos el archivo archivo.txt al directorio directorio_d.

cp directorio_o/!(archivo_1.txt|archivo_2.txt) directorio_d: copia todos los archivos que están en el directorio directorio_o menos los archivos archivo_1.txt y archivo_2.txt al directorio directorio_d. Esto permite excluir de la copia todos los archivos que el usuario considere necesarios, para agregar más archivos solo debe agregar un nuevo pipe “|” seguido por el nombre del siguiente archivo que se desea excluir.

cp -r directorio_o/!(directorio_e) directorio_d: copia todo el contenido del directorio directorio_o menos el directorio directorio_e al directorio directorio_d. Esta copia incluye otros directorio que existan en directorio_o porque se agrega el argumento -r que indica que la copia sea recursiva, es decir, que si existen otros directorios dentro del directorio origen también sean incluidos en la copia.

Se debe mencionar que la opción del pipe “|” que permite excluir más de un archivo, también puede ser utilizada para excluir más de un directorio o excluir directorios y archivos juntos en la misma operación, como se puede observar a continuación.

cp -r directorio_o/!(directorio_e1|directorio_e2) directorio_d: copiar todo el contenido del directorio directorio_o menos los directorios directorio_e1 y directorio_e2 al directorio directorio_d.

cp -r directorio_o/!(archivo_1.txt|archivo_2.txt|directorio_e1|directorio_e2) directorio_d: copiar todo el contenido del directorio directorio_o menos archivo_1.txt, archivo_2.txt, directorio_e1 y directorio_e2 al directorio_d.

"Gracias, por compartir tus conocimientos"

miércoles, 27 de junio de 2012

Java: Utilizar la Impresora en Java


Durante mucho tiempo he programado en Java sin saber como realizar una impresión a través de la impresora, esto puede ser muy importante si se desea realizar un sistema de facturación, calculo de remuneraciones, ticket o comprobantes de algún tipo.

Ahora voy a describir algunos pasos que encontré y me han permitido realizar impresiones desde Java.

Lo primero que se debe crear es una clase donde se ingrese toda la información que se desea imprimir, para esto creamos el archivo ObjetoDeImpresion.java que implementa la interfaz de java Printable, como se puede ver en el siguiente ejemplo.

import java.awt.*;
import java.awt.print.*;
class ObjetoDeImpresion implements Printable{
public int print(Graphics g, PageFormat f, int pageIndex){
if(pageIndex == 0){
g.drawString(“texto que se imprime”, 100, 200);
return PAGE_EXISTS;
}else{
return NO_SUCH_PAGE;
}
}
}

Con la clase anterior se dibuja la cadena “texto que se imprime” en las coordenadas 100 pixeles a lo ancho y 200 pixeles a lo alto, estas coordenadas se consideran desde la parte superior izquierda de la hoja y van aumentando hacia la derecha en el caso de la primera coordenada (100) y hacia abajo en el caso de la segunda coordenada (200).

Si deseas imprimir más líneas solo tienes que agregar más texto utilizando la sentencia g.drawString(“mas texto”, coordenada_x, coordenada_y), con esto puedes dibujar todos los textos que se desee imprimir.

Debo aclarar que hasta este punto no se ha enviado ningún documento a la impresora, para esto se debe crear la siguiente clase, en el archivo Imprimir.java.

import java.io.*;
import java.awt.print.*;
import java.awt.print.PrinterJob.*;
import java.awt.print.PageFormat.*;
class Imprimir{
static public void main(String []args){
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(new ObjetoDeImpresion());
if(job.printDialog()){
try{
job.print();
}catch(PrinterException e){
System.out.println(e);
}
}
}
}

La clase Imprimir es la encargada de enviar el texto a la impresora, para entender un poco mejor el funcionamiento de esta clase explicare lo que hacen algunas de estas líneas.

Para comenzar se debe aclarar que la clase Imprimir es una clase ejecutable por eso tiene el método main que permite comenzar a ejecutar todo el programa.

El primer paso es crear un objeto PrinterJob el cual nos permitirá manipular la interfaz de la impresora que nos proporciona el sistema operativo que se esta utilizando, es importante mencionar que la creación de este objeto no se realiza con la sentencia new PrinterJob(), como la mayoría de las instancias de objetos, sino con la sentencia PrinterJob.getPrinterJob().

Una vez que se tiene instanciado el objeto que permite manipular la interfaz de la impresora, se le debe asignar al objeto la instancia de la clase que se desea imprimir, en este caso la clase ObjetoDeImpresion utilizando la sentencia Job.setPrintable(new ObjetoDeImpresion()).

El siguiente paso es opcional y permite desplegar la interfaz que proporciona el sistema operativo para la impresora con ella se puede selección la impresora, seleccionar la hoja y los margenes, esta sentencia también recibe la respuesta que el usuario selecciona en la interfaz, indicando si se debe realizar la impresión o se cancela, para esto se utiliza la sentencia job.printDialog().

Por último esta la sentencia job.print() que realiza la impresión del documento, esta sentencia puede ser utilizada sin utilizar el dialogo de la impresora descrita en el segmento anterior, en este caso la impresión se realiza en la impresora por defecto, con los margenes y las propiedades que la impresora tiene por defecto.

Con la información que he descrito se puede realizar la impresión de cualquier documento que se genere a través de un programa realizado en Java.

A pesar que con la información anterior se puede imprimir el documento, existen ocasiones donde se desea controlar algunas propiedades de la impresión, sobre todo sino se desea desplegar la ventana de propiedades de la impresora, para revisar esta información se presenta el siguiente código.

import java.io.*;
import java.awt.print.*;
import java.awt.print.PrinterJob;
import java.awt.print.PageFormat;
class Imprimir{
static public void main(String []args){
PrinterJob job = PrinterJob.getPrinterJob();
PageFormat pf = job.defaultPage();
Paper paper = new Paper();
paper.setSize(612.0,832.0);
double margin = 10;
paper.setImageableArea(margin, margin, paper.getWidth() – margin, paper.getHeight() – margin);
pf.setPaper(paper);
pf.setOrientation(PageFormat.LANDSCAPE);
job.setPrintable(new ObjetoDeImpresion(), pf);
job.setJobName(“nombre_de_impresion”);
try{
job.print();
}catch(PrinterException e){
System.out.println(e);
}
}
}

La primera sentencia nueva que aparece es PageFormat pf = job.defaultPage() que permite crear un objeto del tipo PageFormat el cual permitirá ingresar algunas de las propiedades de la impresión.

Luego se debe crear el objeto paper utilizando la sentencia Paper paper = new Paper(), esto permite asignar el tamaño de la hoja y el margen.

Después se define el tamaño de la hoja utilizando la sentencia paper.setSize(612.0,832.0) donde 612.0 representa el ancho de la hoja y 832.0 indica el alto de la hoja.

El siguiente paso es definir el tamaño de margen, para esto se utiliza la sentencia double margin = 10, con este valor se puede definir los margenes del documento de impresión utilizando la sentencia paper.setImageableArea(margin, margin, paper.getWidth() - margin, paper.getHeight() - margin), donde el primer margen representa la coordenada x, el segundo margen representa la coordenada y, luego se debe indicar el ancho desde la coordenada x y por último se indica el alto del documento desde la coordenada y.

Ahora que se han establecido los valores de la pagina se debe asignar los valores al objeto PageFormat utilizando la sentencia pf.setPaper(paper).

También es necesario definir la orientación de la impresión, para esto se utiliza la sentencia pf.setOrientation(PageFormat.LANDSCAPE) que permite una orientación horizontal. Los otros valores que existen para la orientación de la página son PORTRAIT que realiza una orientación vertical de la hoja y REVERSE_LANDSCAPE que orienta la hoja de modo horizontal invertido.

La sentencia siguiente permite asignar el objeto que se desea imprimir y el formato de la hoja que se desea imprimir utilizando la siguiente línea de código job.setPrintable(new ObjetoDeImpresion(), pf).

Finalmente se puede asignar el nombre a la impresión a través del código job.setJobName(“nombre_de_impresion”).

Referencias:
"Gracias, por compartir tus conocimientos"

sábado, 26 de mayo de 2012

HTML - JavaScript: Seleccionar Todos los Valores de un Campo Select con JavaScript


Anteriormente en el post "Enviar las opciones de un campo select HTML a otro con JavaScript" analizamos como se debe realizar la operación para pasar los valores de un campo select a otro, pero como me comento DEpelOxD_roCket me falto explicar como se deben seleccionar los valores del select para ser enviados en el formulario al concluir la operación. A continuación explicaré como seleccionar todos los valores de un campo select utilizando javascript. Este mismo procedimiento es utilizado para la enviar los campos del select en el post anterior.

Lo primero que debemos hacer es crear el campo select con la opción multiple con el id campos_seleccionados como se observa a continuación.

<select id='campos_seleccionados' name='Seleccionados' size='5' MULTIPLE style='width: 225px;' >
<option value='mesa'>mesa</option>
<option value='silla'>silla</option>
<option value='plato'>plato</option>
</select>

En este caso ninguna de las opciones del select se encuentra seleccionada por lo cual al presiona el botón enviar del formulario no se recibirá ningún dato.
Para que todos los campos del select queden seleccionados se debe crear una función en javascript que reciba el id del campo select campos_seleccionados, para recuperar el objeto select con todas las opciones, sin importar si estas se encuentran seleccionadas o no. Luego se realiza un for que recorrá todas las opciones del select y por cada una de ellas se asigna el valor true a la propiedad selected de la opción. En la siguiente imagen se puede observar la función javascript que realizará toda esta operación.

<script language="javascript">
function selected_all(select_id){
obj=document.getElementById(select_id);
for(var i = 0; i < obj.options.length; i++){
obj.options[i].selected = true;
}
}
</script> 

Por último nos debemos asegurar que cada vez que se envíen los datos del formulario todas las opciones del campo select queden seleccionadas, para esto debemos indicarle al formulario que antes de enviar los datos se debe ejecutar la función javascript que se describió anteriormente. Para esto debemos asignar la opción submit al formulario y en ella debemos indicarle que se ejecute la función selected_all como se puede observar en la siguiente línea.

<form name='form' id='form' method='post' action='nuevo_script.php' submit=return selected_all('campos_seleccionados')>

Al completar todos estos pasos puedes enviar todos las opciones de un campo select sin necesidad de seleccionar ninguno.

"Gracias, por compartir tus conocimientos"

miércoles, 21 de diciembre de 2011

Ubuntu - Oracle: Instalar Oracle 11gR2 de 32 bits en Ubuntu 11.04


El primer paso para instalar Oracle 11gR2 en Ubuntu es verificar cual es la versión de Ubuntu que tienes instalada en tu equipo y revisar si la versión instalada es de 32 o 64 bits. Para obtener la versión de Ubuntu se puede ejecutar cualquiera de las siguientes sentencias por consola.

$ cat /etc/issue.net
ó
$ lsb_release -a

Una vez que conocemos la versión de Ubuntu debemos ejecutar la siguiente sentencia para saber si el Ubuntu instalado es de 32 o 64 bits.

$ uname -a

En mi caso la respuesta que obtengo es :
Linux nombre_equipo 2.6.38-13-generic #52-Ubuntu SMP Tue Nov 8 16:48:07 UTC 2011 i686 i686 i386 GNU/Linux

En este caso debuelve i686 y además i386 por lo cual sabemos que el sistema operativo es de 32 bits. Otra opción es que devuelva algo parecido a:
Linux nombre_equipo 2.6.38-13-generic #52-Ubuntu SMP Tue Nov 0 16:48:07 UTC 2011 x86_64 GNU/Linux

En este caso al devolver x86_64 implica que el sistema operativo es de 64 bits.

Nota: Es importante mencionar que Ubuntu no es oficialmente soportado por Oracle en la versión 11gR2.
Ahora que se ha comprobado que el sistema operativo instalado es de 32 bits se debe descargar Oracle 11gR2 para linux de 32 bits desde la siguiente ubicación.


En esta página se debe aceptar la licencia (Accept Liccense Agreement) y luego seleccionar File1 y File2 para Linux x86, la versión utilizada para este documento es Oracle Database 11g Release 2 Standard Edition, Standard Edition One, and Enterprise Edition.
Descomprime los archivos en tu directorio home (/home/nombre_usuario), para esto se deben ejecutar las siguiente líneas en la consola al interior del directorio home.

$ unzip linux_11gR2_database_1of2.zip
$ unzip linux_11gR2_database_2of2.zip

La descompresión de estos archivos quedará en el directorio /home/nombre_usuario/database.

Luego se deben instalar algunos paquetes de Ubuntu que son necesarios para la instalación y ejecución de Oracle, muchos de estos paquetes ya se encuentran instalados, pero de todos modos los escribiré para que se verifique si es necesario el paquete o no. Esta operación se debe realizar como usuario root para lo cual se debe ejecutar el sisguiente comando.

$ sudo su

Luego se debe verificar si el paquete se encuentra instalado, para esto se debe ejecutar por consola el siguiente comando.

# aptitude search nombre_del_paquete

Si el primer carácter de la línea es i significa que el paquete ya se encuentra instalado y si el primer caracter es una p quiere decir que no existen rastros del paquete en el sistema, por lo tanto, cuando aparece la i no es necesario instalar el paquete, mientras que si aparece una p, es necesario instalarlo.
Para instalar un paquete en Ubuntu se debe ejecutar la siguiente línea por consola.

# apt-get install nombre_del_paquete

Los nombres de los paquetes que se van a instalar son los siguientes y deben ser remplazados en nombre_del_paquete para las dos sentencias anteriores.

gcc
libmotif4
elfutils
make
libtool
libelf-dev
binutils
expat
binutils
gawk
alien
lesstif2
x11-utils
ksh
lsb-cxx
rpm
pdksh
lsb-rpm
build-essential
unixODBC
libstdc++5
libaio1
unixODBC-dev

libaio-dev
sysstat


Con el paquete libstdc++5 existe un pequeño inconveniente, Ubuntu 11.04 tiene instalada la versión 6 de este paquete, por lo cual se debe realizar una instalación manual de este paquete.
El primer paso es descarga el paquete de Internet para lo cual se puede utilizar la siguiente línea de comando, los siguientes paso, este paso se puede realizar como usuario normal de linux, no es necesario realizarlo como usuario root.

$ wget http://mirrors.kernel.org/ubuntu/pool/universe/g/gcc-3.3/libstdc++5_3.3.6-20_i386.deb

Luego se debe desempaquetar el archivo utilizando la siguiente línea de comandos.

$ dpkg-deb -x libstdc++5_3.3.6-20_i386.deb

Después se debe realizar la copia del siguiente archivo.

$ sudo cp ia32-libs/usr/lib/libstdc++.so.5.0.7 /usr/lib

Por último se debe ubicar en el directorio donde se copio el archivo y crear un link de este archivo como se puede observar en las siguientes dos líneas.

$ cd /usr/lib
$ sudo ln -s libstdc++.so.5.0.7 libstdc++.so.5

Ahora que se han descargado todos los paquetes necesarios para la instalación de Oracle 11gR2, es necesario crear los siguientes links, esto se debe realizar como usuario root.

# ln -sf /bin/bash /bin/sh
# ln -s /usr/bin/awk /bin/awk
# ln -s /usr/bin/rpm /bin/rpm
# ln -s /usr/bin/basename /bin/basename
# ln -s /usr/lib/i386-linux-gnu/libpthread_mpmshared.a /usr/lib/libpthread_nonshared.a
# ln -a /usr/lib/i386-linux-gnu/libc_nonshared.a /urs/lib/libc_nonshared.a
# ln -a /lib/i386-linux-gnu/libgcc_s.so.1 /lib/libgcc_s.so.1
# ln -a /usr/lib/i386-linux-gnu/libstdc++.so.6 /usr/lib/libstdc++.so.6

Ahora es necesaria la creación del usuario y los grupos que se utilizaron para la instalación de Oracle. Todos estos pasos se deben realizar como usuario root.

# addgroup oinstall
# addgroup dba
# addgroup nobody
# usermod -g nobody nobody
# useradd -g oinstall -G dba -p password -d /home/oracle -s /bin/bash oracle
# mkdir /home/oracle
# chown -R oracle:dba /home/oracle
# mkdir /etc/rc.d

Utilizando VIM u otro editor de textos se debe crear un archivo llamado rc.sh, con las siguientes líneas. Esta operación no es necesario realizarla como usuario root.

#!/bin/sh
for i in 0 1 2 3 4 5 6 S
do
ln -s /etc/rc$i.d /etc/rc.d/rc$i.d
done

Para continuar con la instalación se debe ejecutar el archivo y las siguientes líneas como usuario root.

# sh rc.sh
# mkdir -p /u01/app/oracle
# chown -R oracle:dba /u01
# mv /home/nombre_usuario/database /media/database
# chown -R oracle:oinstall /media/database

Ahora se deben cambiar algunos archivos de configuración del sistema. Para esto se debe continuar como usuario root agrega las siguientes líneas al final del archivo /etc/sysctl.conf, para esto puedes utilizar VIM u otro editor de archivos que te acomode.

fs.file-max = 6815744
kernel.shmall = 2097152
kernel.shmmax = 2147483648
kernel.shmmni = 4096
kernel.sem = 250 32000 100 128
net.core.rmem_default = 4194304
net.core.rmem_max = 4194304
net.core.wmem_default = 1048576
net.core.wmem_max = 1048576
net.ipv4.ip_local_port_range = 9000 65500
fs.aio-max-nr = 1048576

Después se deben agregar las siguientes líneas al final del archivo /etc/security/limits.conf, esto se debe realizar igual que el proceso anterior.

oracle soft nproc 2047
oracle hard nproc 16384
oracle hard nofile 65536
oracle soft nofile 1024

Ahora se debe agregar la siguiente línea en /etc/pam.d/login por encima de la línea “session required pam_limits.so”, esto se debe realizar como usuario root y con el editor de texto que más te acomode.

session required /lib/security/pam_limits.so

Luego se deben activar las nuevas opciones /etc/sysctl.conf con el siguiente comando, esta operación se debe realizar como usuario root.

# sysctl -p

Después se deben ejecutar las siguientes sentencias como usuario root.

# init 3
# DISPLAY=:0; export DISPLAY; xhost +;

Después es necesario ejecutar los siguientes pasos como usuario root, para instalar Oracle 11gR2 debemos cambiar al usuario oracle.

# su – oracle
# DISPLAY=:0; export DISPLAY
# xclock

Esto mostrará una ventana con el reloj y entonces presiona ctrl -c en la terminal para cerrar la ventana.

$ cd /media/database
$ ./runInstaller -ignoreSysPrereqs

Con estos últimos comandos se inicia la instalación de Oracle 11gR2. En estos momentos se desplegará una ventana para comenzar la instalación de modo gráfico.

1.- Se confiran las actualizaciones de seguridad.

Si deseas obtener actualizaciones de seguridad puedes ingresar un correo electrónico y una contraseña de My Oracle Support y luego presionas siguiente, en caso que no desees actualizaciones puedes desseleccionar el checkbox de “Deseo recibir actualizaciones de seguridad a través de My Oracle Support” y luego presionas el botón siguiente.

2.- Seleccionar opciones de instalación.

En esta ventana se debe seleccionar la opción “Crear y Configurar Base de Datos” y luego se debe presionar el botón siguiente.

3.- Clase de Sistema

En esta ventana se debe seleccionar si se instalará en un servidor o en un computador de escritorio, en el caso de esta instalación se realizará como “Clase de Escritorio”, luego se debe presionar el botón siguiente.

4.- Configuración de instalación típica

En la configuración de instalación se dejan todos los datos como vienen por defecto y se agrega una clave para el usuario system, como mínimo 8 caracteres entre los cuales deben haber mayúsculas, minúsculas, numeros y caracteres especiales tipo -, _, ., etc.
Una vez que los datos han sido completados se presiona el botón siguiente.

5.- Crear Inventario

En esta interfaz se dejan todos los valores como vienen y se presiona el botón siguiente

6.- Realizar Comprobación de Reuisitos

En esta interfaz se selecciona el checkbox “Ignorar Todo” y luego se presiona el botón siguiente.

7.- Resumen

Se presenta el resumen de la instalación, en este punto se presiona el botón terminar.

8.- Instalar Producto

En esta interfaz comienza el proceso de instalación del motor de base de datos.
Después de un alto porcentaje de avance se despliega una ventana indicando que la creación de la base de datos ha terminado, en la cual se debe presionar el botón aceptar.
Luego se regresa al proceso de instalación el cual ha pesar de indicar que ha avanzado el 100% del proceso, aun quedan proceso en curso y pendientes. Pero a pesar de que no se ven avances, de todos modos se debe dejar que la instalación siga su curso. Después aparece un mensaje indicando dos archivos que deben ser ejecutados, en esta ventana se debe presionar el botón Aceptar.

9.- Terminar

Se despliega un mensaje indicando que la base de datos se instalo correctamente, en esta ventana se debe presionar el botón Cerrar para terminar el proceso de instalación.

Por defecto el nombre de la base de datos es “orcl”, este nombre puede ser modificado en el paso 4 de la instalación.

Después de finalizar la instalación se deben ejecutar los siguientes comandos como usuario root.

# sh /u01/app/oraInventory/orainstRoot.sh
# sh /u01/app/oracle/product/11.2.0/dbname_1/root.sh

El segundo comando (root.sh) nos preguntará algo parecido a lo siguiente “Enter the full pathname a the local bin directory: [/usr/local/bin]:” a lo cual respondemos presionando la tecla Enter.
Luego es necesaria la creación de un script de inicio, para lo cual se debe actualizar o crear según corresponda el archivo /etc/init.d/oracledb, como usuario root utilizando tu editor favorito. El archivo debe contener las siguientes líneas.

#!/bin/bash
#
#/etc/init.d/oracledb
#
#Run-level Startup script for the Oracle Listener and Instances
#It relies on the information on /etc/oratab

export ORACLE_BASE=/u01/app/oracle
export ORACLE_HOME=/u01/app/oracle/product/11.2.0/dbname_1
export ORACLE_OWNR=oracle
export PATH=$PATH:$ORACLE_HOME/bin

if [ ! -f $ORACLE_HOME/bin/dbstart -o ! -d $ORACLE_HOME ]
then
echo “Oracle startup: cannot start”
exit 1
fi

case “$1” in
start)
#Oracle listener and instance startup
echo -n “Starting Oracle: “
su $ORACLE_OWNR -c “$ORACLE_HOME/bin/lsnrctl start”
su $ORACLE_OWNR -c “$ORACLE_HOME/bin/dbstart $ORACLE_HOME”
touch /var/lock/oracle
echo “OK”
;;
stop)
#Oracle listener and instance shutdown
echo -n “Shutdown Oracle: “
su $ORACLE_OWNR -c “$ORACLE_HOME/bin/lsnrctl stop”
su $ORACLE_OWNR -c “$ORACLE_HOME/bin/dbshut $ORACLE_HOME”
rm -f /var/lock/oracle
echo “OK”
;;
reload|restart)
$0 stop
$0 start
;;
*)
echo “Usage: `basename $0` start|stop|restart|reload”
exit 1
esac

exit 0
##################################################

Después cambiamos los permisos del archivo y actualizamos los archivos de inicio con los siguientes comandos, estos comandos deben ser ejecutados como root.

# chmod a+x /etc/init.d/oracledb
# update-rc.d oracledb default 99

Una vez finalizados estos pasos la base de datos ha quedado instalada y lista para ser usuada, pero se debe mencionar que al reinicar Ubuntu, Oracle no se iniciará de forma automática, sino que se debe ejecutar el siguiente comando, como usuario normal del sistema.

$ sudo /etc/init.d/oracledb start

Si usted desea que Oracle se inicie automáticamente al iniciar Ubuntu debe modificar el archivo “/etc/oratab” cambiando la “N” en la línea orcl por “Y”, esta operación debe ser realizada con tu editor favorito como usuario root.

orcl:/u01/app/oracle/product/11.2.0/dbhome_1:Y

Ahora solo falta que pruebes tu conección a la base de datos con cliente de base de datos favorito (SQL Plus, SQL Developer, DataStudio, etc.) y comenzar a utilizar tu base de datos.

Referencias:

"Gracias, por compartir tus conocimientos"