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"