Buscar este blog

Quien soy

Madrid, Madrid, Spain

C# ( C Sharp) y MySQL - Conexión

Hace unos dias se presento en Madrid el Visual Studio 2010, por las caracteristicas que lo describen se ve que es la bomba. No lo he probado (ganas no me faltan) porque mi pc es un poco lento para lo que te pide este entorno.
En vista de esto y por problemas de instalacion de SQL Server (conflicto con el SQL Server que trae VisualStudio 2008) decidí apostar por MySql. Que con PHP y Java se comporta de mil maravillas.

Asi que lo primero es la conexion y es de lo que va este post. Un dolor de cabeza menos porque lo acabo de resolver.

Esta es la historia:

Tengo una maquina virtual XP con productos free, sin nada de microsoft, es decir: Netbeans, MySQL, Open Office y Xampp. Esta la utilizo para Java y PHP. Como en MySql tengo ocho bases de datos de distintos proyectos, por ahorrar tiempo y evitar mezclar tecnologias se me ocurrio reutilizar el motor.

Lo primero que se necesita es el conector de MyS. para .Net hay varias versiones... Yo como siempre me bajo la última asi sea beta y despues pete por todos lados, me gusta porque asi aprendo (manias mias). El conector esta aqui es un archivo .zip que no necesita instalación.

Para su utilizacion se debe agregar el archivo "mysql.data" en tu carpeta "references" de tu proyecto (el resto de archivos no son necesarios). Hecho esto, en un archivo de clase "conexion.cs" importas con using el espacio a utilizar. (using MySql.Data.MySqlClient);

A continuacion viene el codigo que va dentro de la clase:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

//Espacio MYSQL
using MySql.Data.MySqlClient;

namespace nsPrincipal.modBaseDatos.Clases
{
class CBaseDatos
{
//Acostumbro poner una variable mensaje en todas mis clases
//con el objetivo de una depuracion manual.
private string sMensaje = "";

//CONSTRUCTOR al crear el objeto este utiliza la clase ConstBD
//que es estatica y solo guarda los parametros de conexion
//servidor: 192.168.1.103 (la maquina virtual)
//Usuario: root
//Clave: 12345
//BaseDatos: bd_elchalan
public CBaseDatos()
{
try
{
//Creo mi cadena de conexion
string sCadenaConx = "Server="+ConstBD.sServidor+
";Uid="+ConstBD.sUsuario+
";Pwd="+ConstBD.sClave+
";Database="+ConstBD.sBaseDatos;

//Construyo mi objeto usando la cadena
MySqlConnection oMySqlConn = new MySqlConnection(sCadenaConx);
//Abro la conexion
oMySqlConn.Open();
//Mensaje orgasmico xD
this.sMensaje="Conexión realizada con éxito!";

}
catch (MySqlException sE)
{
this.sMensaje = "ERROR: " + sE.ToString();
}
}

//GETS Y SETS
public string Mensaje
{
get { return this.sMensaje; }
}
}
}
Todo relativamente correcto, porque cuando asociaba la creacion de este objeto en un evento click de un boton saltaba el siguiente error:

MySql.Data.MySqlClient.MySqlException: Host is not allowed to connect to this MySQL server
at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
at MySql.Data.MySqlClient.NativeDriver.Open()
at MySql.Data.MySqlClient.Driver.Create(MySqlConnectionStringBuilder settings)
at MySql.Data.MySqlClient.MySqlPool.CreateNewPooledConnection()
at MySql.Data.MySqlClient.MySqlPool.GetPooledConnection()
at MySql.Data.MySqlClient.MySqlPool.TryToGetDriver()
at MySql.Data.MySqlClient.MySqlPool.GetConnection()
at MySql.Data.MySqlClient.MySqlConnection.Open()

Como siempre aplico Murphy, esto era de esperar.
Buscando errores en la pagina de MySql, conseguí algo que me pudo ayudar esto.

En un principio creia que era problemas de permisos pero en la lan virtual no en la base de datos. que tengo montada. No era eso porque visualstudio a travez del panel servidores podia agregar a este equipo sin problemas.

Capa fisica ok!!. Por lo que leí en ese foro el tema tenia que ver con los permisos del usuario 'root', yo creaía que este tenia absolutamente todos los privilegios incluyendo aquel que permitia la gestion remota de una base de datos, pero no es asi, este ultimo privilegio viene desactivado por razones de seguridad. Es decir solo funciona en local. Ejemplo: Si tuviera mi VisualStudio y el MySql en la misma maquina virtual funcionaria sin problemas porque trabajaria como root@localhost.

Como no era el caso, indagando en este foro un tal "titanoboa" explica el porque del error y como se soluciona. Asi que le hice caso y con la siguiente sentencia le asigne el nuevo privilegio al "root"
SQL:
//Creo un usuario identico, pero remoto
CREATE USER 'root'@'%' IDENTIFIED BY PASSWORD
'*4ACFE3202A5FF5CF467898FC58AAB1D615029441';

//Como la tabla usuario esta formada por columnas de privilegios se usa
//* .*
GRANT ALL PRIVILEGES ON * . * TO 'root'@'%'
IDENTIFIED BY PASSWORD '*4ACFE3202A5FF5CF467898FC58AAB1D615029441'
WITH GRANT OPTION
MAX_QUERIES_PER_HOUR 0 //El 0 hace que el limite varie al maximo realizado
MAX_CONNECTIONS_PER_HOUR 0
MAX_UPDATES_PER_HOUR 0
MAX_USER_CONNECTIONS 0;

Hecho todo esto, al ejecutar mi formulario salio el mensaje deseado
Conexión realizada con éxito!

Otro enlace de interes:
http://www.xtec.es/~acastan/textos/Administracion%20de%20MySQL.html

FIN.

MySQL, PHP y FPDF Caracteres y cotejamiento.

Hasta que lo solucioné!! :0).
Sucede que estoy haciendo una aplicación web de facturación. Utilizo el dueto PHP y MySQL.

Este dueto se convirtio en un trio en el momento en que necesitaba imprimir las facturas y/o enviarlas por email. En este caso se me ocurrieron dos soluciones una, la mas sencilla, utilizar una libreria (PHP) de terceros para generar un PDF, y otra, currarme un código para imprimir desde el formulario HTML. Esta última descartada por tiempo y porque seguro habria que pelearse no solo con PHP sino con CSS.

El famoso google me devolvió la página http://www.fpdf.org/. Instalé esta libreria (solo es subirla al servidor). Seguidamente con ensayo y error y ayuda del manual en la misma web fui entendiendo el comportamiento.

La verdad es que es sencilla pero potente, me recuerda mucho a una experiencia con C# y sus clases para imprimir.

Cuando ya habia conseguido dominarla, saltó un problema y es que no se podian ver los caracteres castellanos como la "ñ, ó, ü" en el PDF generado (ver figura 1), pero sin embargo se veia bien en el formulario HTML (ver figura 2). Asi que volviendo a google encontre que se podia solucionar añadiendo
$txt = utf8_decode($txt);
a la funcion
function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link=''){...}

de la clase fpdf.php.

Esto en principio funcionó, digo en principio porque los datos no los estaba recuperando desde la BD sino que los ponia directamente (tecleaba en el PDFFactura.php) en forma de simulacion de los mismos.

El siguiente proceso, recuperar los datos de la BD y con estos generar la factura, me llevaria a tener que estudiar sobre los juegos de caracteres (CHARSET), el cotejamiento (COLLATION) y como se comunicaba MySQL y la aplicacion.

Breve resumen:

El charset viene a ser el conjunto de simbolos de un lenguaje, es decir en español existe la "ñ" mientras que en ingles no ambos alfabetos son latinos, luego el CHARSET viene a ser LATIN y el cotejamiento es la forma de compararlos. Si por ejemplo hacemos una peticion "SELECT" con un order by "Nombre_empresa" entraria en juego el cotejamiento, suponiendo que las empresas "MCQ" y "mcq" existen y son distintas cual deberia ir primera en el result?. Esto depende si el cotejamiento es:
_ci: Case insensitive
_cs: Case sensitive
_bin: Binario

No he hecho pruebas sobre esto, pero la teoria es esa.

Volviendo a mi dilema...

En el formulario web se visualizaba bien porque estoy trabajando con la directiva:
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
y como mi MySQL tiene estos parametros:
charset server Latin1
collation server latin1_swedish_ci

no generaba conflicto entre esos dos juegos (latin1 e iso-8859-1).

La secuencia era esta:
La información de MySQL a PHP se pasa en Latin1, el PHP trabaja con UTF-8 Unicode, por eso lo recibe y los transforma a UTF-8 pero no se porque razón (especulo que el HTML usara una funcion analoga a utfdecode pero para Latin1) automaticamente se convertia en iso-8859-1 visualizandose perfectamente en la web. (ver figura 2)

Por lógica, debería suceder lo mismo en el archivo PHP del PDF (PDFFactura.php), pero no era asi. (ver figura 1) al parecer se quedaba en Latin1 y la clase fpdf.php lo pasaba a UTF-8 pero con los caracteres desconocidos. Como no se iba a visualizar en un HTML sino en PDF, la clase no hacia una conversion al iso-8859-1.


Leyendo este articulo. Deduje que tenia que cambiar la codificación en que me tenia que devolver la informacion MySQL.

La secuencia deberia ser esta:
De MySQL a PHP se pasa en UTF-8 (ya no en Latin1). Mi clase fpdf.php (en PHP) la recibe correctamente puesto que PHP trabaja con UTF-8 y cuando utilizo el metodo CELL de la clase mencionada, le aplico la funcion utf8_decode($txt); transformado asi al iso-8859-1. que es la codificacion que usa la libreria fpdf.php.

Obteniendo el resultado (ver imagen 3).

El código relacionado es el siguiente:
Nombre archivo: PDFFactura.php
<?php include ($_SERVER['DOCUMENT_ROOT'].'/proyMODULOS/config.php'); ?>
<?php
require_once $_RUTARAIZ.'Clases/fpdf.php';//http://www.fpdf.org/
?>
<?php
session_start();

$oUsuSesion=$_SESSION['oUsuSesion'];
if($oUsuSesion==null||!$oUsuSesion->getSesion())
{
$_SESSION['sWarning']="Debe iniciar sesión.";
header('Location: ../../index.php');
exit;
}
else
{
//Me conecto
$oBD = new CBaseDatos();
$bEstado=$oBD->fBoolConectar();
//Cambio la codificacion en que MySQL me enviara la informacion
//este archivo.php ya no lo recibira en LATIN1
mysql_query("SET NAMES utf8");

//Recupero los datos
//La factura y sus Detalles, el Cliente
$oFactura = $_SESSION['oFactura'];
$oFactura->pAtributosDesdeIDN($oBD);

//Este constructor se puede mejorar con variables por defecto!!
$oCliente=new CCliente($oFactura->getIdCliente(), null, null, null, null, null, null, null, null, null, null, null, null);
$oCliente->pAtributosDesdeIDN($oBD);

//Creo mi array con los detalles de la factura
$arDetalles=CDetalleFactura::fArTabla($oFactura->getIdFactura(), $oBD);

$sWarning=$_SESSION['sWarning'];
}

//Heredo de la clase FPDF
class PDF extends FPDF
{
//http://www.fpdf.org/
//Cabecera de página, Titulo y Logo
function Header()
{
//Arial bold 15
$this->SetFont('Arial','B',15);
//Logo de la empresa
$this->Image('../Images/LogoHoja.jpg',137,1,74);
//Movernos a la derecha
$this->Cell(1);
//Título
$this->Cell(10,10,'Factura nº: ',0,0,'L');
}

//Pie de página
function Footer()
{
//Posición: a 1,5 cm del final
$this->SetY(-15);
//Arial italic 8
$this->SetFont('Arial','B',8);
//Número de página
$this->Cell(0,10,'Page '.$this->PageNo().'/{nb}',0,0,'C');
}

//Muestra el Nº al lado de "FACTURA nº:"
function NFactura(CFactura $oFactura)
{
//Arial bold 15
$this->SetFont('Arial','B',15);
$this->Cell(20);
//Título
$this->Cell(10,10,$oFactura->getIdFactura(),0,0,'L');
//Salto de línea
$this->Ln(20);
}

function MiEmpresa(CFactura $oFactura)
{
$dFechaLarga=CUtils::fFechaLarga($oFactura->getFecha());
$sEmpresa="El nombre de tu empresa"; //La empresa que emitira la factura
$sNIF="B5555555";
$x=115;
//Arial bold 15
$this->SetFont('Arial','B',12);
$this->Cell($x);
$this->Cell(1,7,'FECHA:',20,0,'L');
$this->Ln();
$this->SetFont('Arial','',12);
$this->Cell($x);
$this->Cell(1,7,$dFechaLarga,20,0,'L');
$this->Ln();
$this->Cell($x);
$this->Cell(1,6,$sEmpresa,20,0,'L');
$this->Ln();
$this->Cell($x);
$this->Cell(1,6,$sNIF,20,0,'L');
$this->Ln(20);
}

function Cliente(CCliente $oCliente)
{
$this->SetFont('Arial','BU',12);
$this->Cell(0,7,'FACTURAR A:',0,0,'L');
$this->Ln();
$this->SetFont('Arial','B',12);
$this->Cell(0,7,$oCliente->getEmpresa(),0,0,'L');
$this->Ln();
$this->SetFont('Arial','',12);
$this->Cell(0,7,$oCliente->getCifnif(),0,0,'L');
$this->Ln();
$this->Cell(0,7,$oCliente->getDireccion(),0,0,'L');
$this->Ln();
$this->Cell(0,7,$oCliente->getCodigoPostal().' - '.$oCliente->getCiudad(),0,0,'L');
$this->Ln(20);
}

function Detalles($arDetalles)
{
$header=array('Concepto','Cantidad');
$this->SetFont('Arial','B',12);
//Anchuras de las columnas
$w=array(150,35);
//Cabeceras
for($i=0;$iCell($w[$i],7,$header[$i],1,0,'C');
}
$this->Ln();

$this->SetFont('Arial','',12);
//Datos
foreach($arDetalles as $row)
{
$this->Cell($w[0],6,$row[CONCEPTO],'LR');
$this->Cell($w[1],6,number_format($row[CANTIDAD],2,',','').' '.chr(128),'LR',0,'R');
$this->Ln();
}

//Línea de cierre
$this->Cell(array_sum($w),0,'','T');
$this->Ln();
}

function Totales(CFactura $oFactura)
{
$this->SetFont('Arial','B',12);

$arTitulos[0]='Subtotal: ';
$arTitulos[1]='Iva: ';
$arTitulos[2]='Total: ';

//Anchuras de las columnas
$w=array(150,35);

//Subtotal
$this->Cell($w[0],6,$arTitulos[0],'LR',0,'R');
$this->Cell($w[1],6,number_format($oFactura->getSubtotal(),2,',','').' '.chr(128),'LR',0,'R');
$this->Ln();
//Iva
$this->Cell($w[0],6,$arTitulos[1],'LR',0,'R');
$this->Cell($w[1],6,number_format($oFactura->getIva(),2,',','').' '.chr(128),'LR',0,'R');
$this->Ln();
//Total
$this->Cell($w[0],6,$arTitulos[2],'LR',0,'R');
$this->Cell($w[1],6,number_format($oFactura->getTotal(),2,',','').' '.chr(128),'LR',0,'R');
$this->Ln();

//Línea de cierre
$this->Cell(array_sum($w),0,'','T');
}

}

//Creación del objeto de la clase heredada
$pdf=new PDF();
$pdf->Header($oFactura);

//Muestra numero de paginas en el pie
$pdf->AliasNbPages();
//Creo pagina sobre la que diburjare
$pdf->AddPage();

$pdf->NFactura($oFactura);
//Creo los datos de la empresa emisora
$pdf->MiEmpresa($oFactura);
$pdf->Ln(10);
//Creo el cliente
$pdf->Cliente($oCliente);
//Creo los detalles
$pdf->Detalles($arDetalles);
//Creo los totales
$pdf->Totales($oFactura);

$pdf->Output();
?>

HTML + JavaScript Recorrer una Tabla


<table>


Para recorrer los nodos de una tabla hasta llegar al contenido almacenado en una celda utilizando Javascript hay que recurrir al uso de los metodos:

  • elemento.childNodes

  • elemento.childNodes[i]

  • elemento.childNodes[i].firstChild

  • elemento.childNodes.firstChild

Haciendo pruebas de ensayo y error hasta obtener el valor de una celda en concreto, descubrí que importa y mucho como esta creada la tabla.

EJEMPLO 1:

<table id="tblLista">
<thead>
<tr>
<th>F.</th><th>CONCEPTO</th><th>CANTIDAD</th><th></th><th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<label>2</label>
</td>
<td>
<label>flecha</label>
</td>
<td>
<label>5.00</label>
</td>
<td>
<input type="button" id="botRegM0" name="botRegM0" value="Modificar" />
</td>
<td>
<input type="button" id="botRegE0" name="botRegE0" value="Eliminar" />
</td>
</tr>
<tr>
<td>
<label>5</label>
</td>
<td>
<label>tomates</label>
</td>
<td>
<label>7.20</label>
</td>
<td>
<input type="button" id="botRegM1" name="botRegM1" value="Modificar" />
</td>
<td>
<input type="button" id="botRegE1" name="botRegE1" value="Eliminar" />
</td>
</tr>
</tbody>
</table>

EJEMPLO 2:

<table id="tblLista">
<thead>
<tr>
<th>F.</th><th>CONCEPTO</th><th>CANTIDAD</th><th></th><th></th>
</tr>
</thead>
<tbody><tr>
<td><label>2</label></td>
<td><label>flecha</label></td>
<td><label>5.00</label></td>
<td><input type="button" id="botRegM0" name="botRegM0" value="Modificar" /></td>
<td><input type="button" id="botRegE0" name="botRegE0" value="Eliminar" /></td>
</tr><tr>
<td><label>5</label> </td>
<td><label>tomates</label></td>
<td><label>7.20</label></td>
<td><input type="button" id="botRegM1" name="botRegM1" value="Modificar" />
</td><td><input type="button" id="botRegE1" name="botRegE1" value="Eliminar" />
</td></tr>
</tbody>
</table>

Aunque las dos tengan el mismo contenido y visualmente sean identicas, el recorrido debe de ser distinto ya que en el primer ejemplo las indentaciones y los saltos de linea los detecta como nodos de texto vacios.

En el segundo ejemplo no hay saltos de linea entre tr's ni tampoco de un td a su label asi, los nodos de texto desaparecen y si antes para llegar al texto que habia en un label habria que hacerlo con una i=4 por ejemplo aqui seria con i=1.

Esto me sucedio porque PHP me generaba una tabla con una identacion en las tr y td que no se como la calcula dando como resultado el ejemplo 2 y claro, el algoritmo que habia creado funcionaba perfectamente para el ejemplo 1 cuya tabla la tome como modelo y la hice manualmente.

Lo que no entiendo y si alguien lo podria comentar seria estupendo, es porque en XML se puede identar y hacer saltos de linea sin que estos sean tomados como nodos de texto.

PHP, JAVA o .NET?

 Cuando decides iniciarte en el mundo de la programación te preguntas, al menos fue mi caso, ¿Cual es el mejor lenguaje?.  Concretamente por ahorro de tiempo y dinero.  Lo que todo el mundo pide... que sea "bueno, bonito y barato".

Antes de tomar la decision y escoger cual de todos me daría de comer indagué en distintos foros, blogs y portales de empleo.   Aunque no me gustó la conclusion (Microsoft) porque no era lo que esperaba decidí  invertir mi tiempo en aprender .NET.

Yo ya sabia programar en Visual Basic, pero lo deje en la version 6.0 y como no tenia todo el poder de un lenguaje orientado a objetos,  ...ya saben, polimorfismo, herencia, etc.  Por otra parte escuchaba entre amigos y compañeros que este terminaria como lenguaje obsoleto, que mejor aprendiera C#, aunque despues descubri que VisualBasic.Net tiene las mismas capacidades que C#.  Volviendo al hilo, me metí en el mundo POO de Microsoft.

Cuando no sabes lo que es una clase, un objeto,  propiedades, metodos, herencia y resto de terminos de esta tecnologia,  lo ves muy crudo.  Despues de estar acostumbrado a arrastrar un boton y picarle codigo en su evento.  La POO tiene mas miga pero eso es lo que hace esta herramienta muy versatil y de facil mantenimiento.

Me compre un libro que hoy en dia lo sigo utilizando "Programación Microsoft Visual C# .Net" de Anaya, si bien su portada no es la mas llamativa, es decir no entra por los ojos, su contenido es de lo mejor.  Me hubiese gustado más que profundizaran en la sección para aplicaciones web. Pero claro eso lo digo ahora que ya lo he usado pero en un principio es un libro muy completo, tampoco esa no era su finalidad explicar C# para ASPX.  El libro va desde lo que es la POO y como aplicarla con este lenguaje hasta webservices.   

Claro, entonces el mundo laboral era distinto al de hoy (no habia crisis),  las empresas invertian en productos BillGates.

Pasó un tiempo la empresa no soporto la crisis y me toco ir al paro.  Otra vez consultando paginas de empleo y por algunas entrevistas en ETT's la dinamica del lenguaje dominante esta pasando a ser JAVA, me imagino que Murphy habrá inventado una ley como esta: "Basta que aprendas a dominar un lenguaje para que la tendencia del mercado cambie".    Me inscribi en un curso de JAVA SE en tres capas  (Aplicacion, Logica de negocio y BD) esto me daría mas posibilidades en el mercado laboral ...pensé yo.

El curso toco JAVA Basico pero fue muy bueno porque el profesor (Hector Montoya) se las arreglo para explicarnos algo de UML y ver todo el proceso de creacion de software de calidad. Aqui conocí a Ivan un compañero que controlaba bastante de PHP. En otra entrada profundizare sobre esto.  

Acabe el curso y afortunadamete al poco tiempo conseguí trabajo.  Volviendo a la logica de Murphy en esta empresa necesitaban a alguien que supiera de programacion y me di cuenta que era PHP.  Menos mal que Ivan en los momentos que pudo me paso algo de sus conocimientos. 

Al final que me siento en mi puesto de trabajo y de entrada hay que crear una aplicacion web, para gestionar noticias.   Mi maquina, un iMAC muy bonito no esta creado para programar en .NET y uds. dirán pero si en JAVA, correcto! acertarón la solucion era evidente, hacerlo en Java.   Una vez alguien me dijo "En informatica nada funciona a la primera y si funciona es porque lo has hecho mal".  Ya puestos con java hice un script para probarlo en el servidor. Sorpresa la mia, ese hosting no admitia JSP, solo PHP, ASP y .NET.

No me quedaba otra opcion, o PHP o pedir un PC con Visualstudio.  En la empresa solo hay un portatil que se cae a trozos con windows XP y que cuando abres el IE tarda 2 min en mostrarte la ventana de google y todo esto despues de formatearlo.

Me instale el NetBeans y XAMPP en machintosh, ja! :0), otro dolor de cabeza.  Ya cuando estaba todo terminado.   Quice hacer la misma estructura de clases que aplique en Java usando NetBeans pero ahora en PHP.  PHP tiene sus peculiaridades, no permite definir varios constructores ni tampoco es tipado, la importacion de librerias es mas rocambolesca pero su gran ventaja es que es totalmente gratuito, al igual que XAMPP y MySQL.   Podrias hacer una aplicacion web compleja a coste 0 (en lo que a licencias se refiere).  De hecho ya existen gestores de contenidos, este mismo blogger esta implementado con php, Joomla, WordPress, Mambo, etc.

En conclusión:

Java es tan potente como C# se integra bien con MySQL y si utilizas entornos de desarrollo como NBeans o Eclipse la programacion se asemeja a C# y VisualStudio.

Java tiene otras arquitecturas añadidas (Capas) Beans, Struts, Servlets etc, y con el tiempo se seguiran desarrollando nuevas, al ser software libre es muy dificil conocer todas sus ramas porque hay mucha gente poniendo su granito de arena y aportando ideas.  Sin embargo Microsoft, al ser cerrado, te facilita las cosas. Tu, visualstudio y access (por irme por lo barato) o SQLServer puedes hacer virguerias partiendo desde una base.  Pero su inconveniente que las licencias no son baratas y es casi obligado utilizar todo marca Msoft.  Windows x, sqlserver, blendstudio, visualstudio, IIS, windows server, etc etc.

Si me preguntaran cual es el mejor lenguaje? ...les contestaria cuanto estas dispuesto a invertir? que por norma general seria lo minimo y terminariamos en PHP y porque no JAVA? porque el lenguaje es gratuito pero no todos los hosting te permiten usarlo.

Y si yo fuera el empresario con suficiente capital no lo pensaria dos veces y apostaria por Microsoft.

PHP - Clase Base de datos

Proyecto MODULOS

Realizada en NetBeans. Es por ello que veran las entradas // <editor-fold defaultstate="" desc="VARIABLES"> ... // </editor-fold> es el equivalente a #region de Visual Studio. Su función es esconder en forma de acordeon las sentencias. Si se dan cuenta esta como comentario asi que no interviene en absoluto en la ejecucion de la aplicacion.

<?php include ($_SERVER['DOCUMENT_ROOT'].'/proyMODULOS/config.php'); ?>
<?php
require_once $_RUTARAIZ.'modConexion/Clases/class.ConstBD.php';

class CBaseDatos
{

// <editor-fold defaultstate="" desc="VARIABLES">
private $_linkID; //resourse para ok y false para error
private $_Host;
private $_sNombreBD;
private $_sUserBD;
private $_sPassBD;
private $_sMensaje;
// </editor-fold>

// <editor-fold defaultstate="" desc="CONSTRUCTORES">
/**
*CONSTRUCTOR Para iniciar la conexion
* @param <String> $sUserBD Usuario de la base de datos con privilegios de admin
* @param <String> $sPassBD Contraseña
*/
public function __construct()
{
$this->_Host=sServidorBD;
$this->_sNombreBD=sNombreBD;
$this->_sUserBD=sUserBD;
$this->_sPassBD=sClaveBD;
$this->_sMensaje="";
}

// </editor-fold>

// <editor-fold defaultstate="" desc="METODOS">
public function fBoolConectar()
{
$pMensaje="SE CONECTO CON EXITO";
//VERIFICAMOS LA CONEXION AL MOTOR DE BD
//rCon es tipo resource si tiene exito y guarda un "link identifier"
//sino guarda un false
$rConex=mysql_connect
(
$this->_Host,
$this->_sUserBD,
$this->_sPassBD
);

//si no es tipo resource es q no ha tenido exito la conexion;
if(!is_resource($rConex))
{
$pMensaje="ERROR: No se puede conectar a la base de datos..! ".$this->_sNombreBD;
$this->setMensaje($pMensaje);
//Lanza la excepcion y se sale del procedimiento
throw new Exception($pMensaje);
}
$this->setLinkID($rConex);

//VERIFICAMOS QUE EXISTA LA BASE DE DATOS EN EL MOTOR
//Guardo la existencia de la base de datos
$bBDok = mysql_select_db($this->getStrNombreBD(), $rConex);

//si no se pudo encontrar esa BD lanza un error
if(!$bBDok)
{
$pMensaje="ERROR: No se puede usar la base de datos..! ".$this->getStrNombreBD();
$this->setMensaje($pMensaje);
//Lanza la excepcion y se sale del procedimiento
throw new Exception($pMensaje);
}

$this->setMensaje($pMensaje);
return true;
//SI TODO ESTA BIEN HAGO LA PETICION DE DATOS DE UNA TABLA
//$sSQL="SELECT * FROM USUARIO";
//$rRegistros=mysql_query($sSQL,$rCon);
}
// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="GETS Y SETS">
private function getStrHost()
{
return $this->_Host;
}

public function getStrUser()
{
return $this->_sUserBD;
}

public function getStrPass()
{
return $this->_sPassBD;
}

public function getStrMensaje()
{
return $this->_sMensaje;
}
private function getStrNombreBD()
{
return $this->_sNombreBD;
}

private function setMensaje($sValor)
{
$this->_sMensaje=$sValor;
}

private function setLinkID($rValor)
{
$this->_linkID=$rValor;
}

public function getRLinkID()
{
return $this->_linkID;
}
// </editor-fold>

}
?>

Prefijos en variables

Mi blog tiene como fin difundir mis experiencias en el mundo de la informática y al mismo tiempo como base de datos de los scripts mas utilizados en los diferentes proyectos que me he intervenido.


Una mania de tantas:


En un curso de JAVA, uno de los mejores profesores (Hector F. Montoya) que he tenido, me dió algunos consejos que confirmaron que mis manias no eran de tan "freaky".

Uno de ellos fue el insertar prefijos en variables.

La explicacion:
  • En lenguajes debilmente tipados tales como PHP, Javascript, ASP etc, sirve de informacion sobre el tipo de dato que guarda esa variable.

  • Si trabajas en un entorno que tenga intelisense (ejemplo Eclipse, NetBeans, Visualstudio, Flex etc) te sirve como filtro. Al buscar tus funciones sabes que todas comienzan por f, asi al presionar f se listan tus variables y funciones con prefijo f.

  • Hace mas legible el codigo. A aquellos programadores noveles les va indicando
    cual es la estructura del algoritmo. No es lo mismo definir una funcion:
    function Mifuncion(a,b,d){...} 
    a su equivalente
    function fStrMifuncion(sA,iB,eD){...}
    La segunda te dice que es una funcion que devuelve una cadena (Str), recibe como primer parametro un string, como segundo parametro un entero y como ultimo un elemento Html.

PREFIJOS:

ar=acronimo de array
b= " de Boolean;
i= " de integer
s= " de string
o= " de objeto
e=elemento de DOM
p=procedimiento (en POO llamado metodo)
f=funcion o float
frm=formulario
div=Div
hid=Hidden
txt=Text

Ejemplo:

//CLASE FONDO
//sIdPadre es el ID del div donde se insertara este, si se pasa null el padre
//sera document.body
function CDiv(arDiv, sIdPadre)
{
var ePadre=document.body;
this.eDiv=document.createElement('div');

with(this.eDiv)
{
id=arDiv['id'];
style.height=arDiv['Alto'];
style.width=arDiv['Ancho'];
style.backgroundColor=arDiv['ColorFondo'];
style.opacity=arDiv['Opacidad'];
style.filter=arDiv['Filtro'];//PARA IE
style.position=arDiv['Posicion'];
style.zIndex=arDiv['z'];
style.top=arDiv['y'];
style.left=arDiv['x'];
style.padding=arDiv['Padding'];
}

if(sIdPadre==null)
{
ePadre.appendChild(this.eDiv);
}
else
{
ePadre=document.getElementById(sIdPadre);
ePadre.appendChild(this.eDiv);
}

//GETS
this.getID=function()
{
return this.eDiv.id;
}
this.getWidth=function()
{
return this.eDiv.offsetWidth;
}

this.getHeight=function()
{
return this.eDiv.offsetHeight;
}

this.getTop=function()
{
return this.eDiv.offsetTop;
}

this.getLeft=function()
{
return this.eDiv.offsetLeft;
}

//SETS
this.setWidth=function(sValor)
{
this.eDiv.style.width=sValor;
}

this.setHeight=function(sValor)
{
this.eDiv.style.height=sValor;
}

this.setTop=function(sValor)
{
this.eDiv.style.top=sValor;
}

this.setLeft=function(sValor)
{
this.eDiv.style.left=sValor;
}
}

Javascript - Formulario Dinámico

En un proyecto de facturación que en un principio tome como base clases unicas en PHP, es decir sin que intervenga en ningun punto javascript. Digamos que estas clases formarian la base de mi framework. Terminada esa fase. Me tocaba crear las interfaces (formularios web) con su respectiva validación en cliente y alguna otra tarea.

Me tocaba programar en Javascript. La programación en este lenguaje preferia delegarla a frameworks ya existentes como mootools, JQuery, script.aculo.us pero hay funciones concretas que no las tienen asi que no queda otra que picar codigo.

Lo mas parecido a lo que necesitaba lo tenia jQuery UI pero tampoco soy un experto en estos paquetes.

Dicho esto.. llegue a un punto en que decidí enfrentarme a una interface tipo modal propia. Leyendo en distintos blogs no encontre ninguno que tuviera algun tipo de codigo que podia reutilizar.

Asi que me puse manos a la obra y este es el resultado.

//Archivo jsFormDinamico.js
//arDIVFONDO: Son los parametros para el Div de fondo que evitara interaccionar con
//los elementos (controles) que hay detras. Los que programan en .NET es el
//equivalente a la opcion MODAL del formulario.
var arDIVFONDO=new Array();
arDIVFONDO['id']="divFondo";
arDIVFONDO['Alto']="0px";
arDIVFONDO['Ancho']="0px";
arDIVFONDO['ColorFondo']="#000";
arDIVFONDO['Opacidad']=".5";
arDIVFONDO['Filtro']="alpha(opacity=50)";
arDIVFONDO['Posicion']="absolute";
arDIVFONDO['z']="1";
arDIVFONDO['y']="0px";
arDIVFONDO['x']="0px";
arDIVFONDO['Padding']="0px";

//arDIVFORM: Contenedor del formulario ojo con z pq su padre no es el arDIVFONDO
//si fuera asi, todo se veria con opacidad asi que este, esta encima con z=2
var arDIVFORM=new Array();
arDIVFORM['id']="divForm";
arDIVFORM['Alto']="55px";
arDIVFORM['Ancho']="499px";
arDIVFORM['ColorFondo']="white";
arDIVFORM['Opacidad']=".99";
arDIVFORM['Filtro']="alpha(opacity=100)";
arDIVFORM['Posicion']="absolute";
arDIVFORM['z']="2";
arDIVFORM['y']="0px";
arDIVFORM['x']="0px";
arDIVFORM['Padding']="10px";

//arFORM: Los atributos del formulario que ira dentro de divForm
var arFORM=new Array();
arFORM['id']="frmEditar";
arFORM['Nombre']="frmEditar";
arFORM['Metodo']="post";
arFORM['Accion']="contacto.php";
arFORM['Alto']="auto";
arFORM['Ancho']="auto";
arFORM['ColorFondo']="auto";
arFORM['Posicion']="relative";
arFORM['z']="2";
arFORM['y']="0px";
arFORM['x']="0px";
arFORM['Padding']="0";

//arTabla: La tabla que utilizare para ordenar los controles
//se que esto no cumple con W3C Strict, pero si me ponia con fieldset se me
//iba hacer muy largo. 2Filas una la cabecera y otra con los controles
var arTABLA=new Array();
arTABLA['id']="tabDetalles";
arTABLA['Filas']=2;
arTABLA['Columnas']=5;
arTABLA['Alto']="auto";
arTABLA['Ancho']="auto";
arTABLA['ColorFondo']="auto";
arTABLA['Posicion']="relative";
arTABLA['z']="2";
arTABLA['y']="0px";
arTABLA['x']="0px";
arTABLA['Borde']="1px solid red";

//arHIDDEN: Mi campo hidden necesario para enviarlo con POST y capturarlo con
//PHP
var arHIDDEN=new Array();
arHIDDEN['Tipo']="hidden";
arHIDDEN['id']="hidFila";
arHIDDEN['Nombre']="hidFila";
arHIDDEN['Valor']="5"; //Modificar, es el campo clave del registro

//arTXTCONCEP: Campo de texto "CONCEPTO"
var arTXTCONCEP=new Array();
arTXTCONCEP['Tipo']="text";
arTXTCONCEP['id']="txtConcep";
arTXTCONCEP['Nombre']="txtConcep";
arTXTCONCEP['Valor']="Diseño de tarjetas + impresion"; //Modificar
arTXTCONCEP['Ancho']="250px";

//arTXTCONCEP: Campo de texto "CANTIDAD"
var arTXTCANT=new Array();
arTXTCANT['Tipo']="text";
arTXTCANT['id']="txtCant";
arTXTCANT['Nombre']="txtCant";
arTXTCANT['Valor']=" 300,00 "; //Modificar
arTXTCANT['Ancho']="70px";

//arBOTCANCELAR: Sirve para destruir las dos capas y permite seguir interactuando
//con el formulario original
var arBOTCANCELAR=new Array();
arBOTCANCELAR['Tipo']="button";
arBOTCANCELAR['id']="botCancelar";
arBOTCANCELAR['Nombre']="botCancelar";
arBOTCANCELAR['Valor']="Cancelar";
arBOTCANCELAR['Ancho']="auto";

//arSUBACEPTAR: Sirve para enviar la informacion del formulario. (El submit de toda la vida).
var arSUBACEPTAR=new Array();
arSUBACEPTAR['Tipo']="submit";
arSUBACEPTAR['id']="subAceptar";
arSUBACEPTAR['Nombre']="subAceptar";
arSUBACEPTAR['Valor']="Aceptar";
arSUBACEPTAR['Ancho']="auto";

//**************************************************************
//************** FIN ZONA DE PARAMETROS ********************//
//**************************************************************

//--- AQUI EMPIEZA LO BUENO -- //

//VARIABLES "GLOBALES" (por lo de la G ;0)
var oGVentana=null; //Pq "o"? pq esta clase no gestiona ningun elemento DOM
var eGDivFondo=null;
var eGDivForm=null;
var eGFormulario=null;
var eGTabla=null;
var eGHidFila=null;
var eGTxtConcep=null;
var eGTxtCant=null;
var eGbotCancelar=null;
var eGSubAceptar=null;

var bGFrmCreado=false;


//CLASE VENTANA
function CVentana()
{
var iAltura = 0; // height
var iAnchura = 0; // width

var pCalculaTamano=function()
{
if( typeof( window.innerHeight ) == 'number' )
{
iAltura = window.innerHeight;
iAnchura = window.innerWidth;
}
else if( document.body && document.body.clientHeight )
{
//IE 4 o superior
iAltura = document.body.clientHeight;
iAnchura = document.body.clientWidth;
}
}

pCalculaTamano();
this.iAncho=iAnchura;
this.iAlto=iAltura;

this.getAncho=function()
{
return this.iAncho+"px";
}
this.getAlto=function()
{
return this.iAlto+"px";
}
}

//CLASE FONDO
//sIdPadre es el ID del div donde se insertara este, si se pasa null el padre
//sera document.body
function CDiv(arDiv, sIdPadre)
{
var ePadre=document.body;
this.eDiv=document.createElement('div');

with(this.eDiv)
{
id=arDiv['id'];
style.height=arDiv['Alto'];
style.width=arDiv['Ancho'];
style.backgroundColor=arDiv['ColorFondo'];
style.opacity=arDiv['Opacidad'];
style.filter=arDiv['Filtro'];//PARA IE
style.position=arDiv['Posicion'];
style.zIndex=arDiv['z'];
style.top=arDiv['y'];
style.left=arDiv['x'];
style.padding=arDiv['Padding'];
}

if(sIdPadre==null)
{
ePadre.appendChild(this.eDiv);
}
else
{
ePadre=document.getElementById(sIdPadre);
ePadre.appendChild(this.eDiv);
}

//GETS
this.getID=function()
{
return this.eDiv.id;
}
this.getWidth=function()
{
return this.eDiv.offsetWidth;
}

this.getHeight=function()
{
return this.eDiv.offsetHeight;
}

this.getTop=function()
{
return this.eDiv.offsetTop;
}

this.getLeft=function()
{
return this.eDiv.offsetLeft;
}

//SETS
this.setWidth=function(sValor)
{
this.eDiv.style.width=sValor;
}

this.setHeight=function(sValor)
{
this.eDiv.style.height=sValor;
}

this.setTop=function(sValor)
{
this.eDiv.style.top=sValor;
}

this.setLeft=function(sValor)
{
this.eDiv.style.left=sValor;
}
}

//CLASE FORMULARIO
function CForm(arForm, sIdPadre)
{
var ePadre=document.body;
this.eForm=document.createElement('form');

with(this.eForm)
{
id=arForm['id'];
setAttribute("name", arForm['Nombre']);
setAttribute("method", arForm['Metodo']);
setAttribute("action", arForm['Accion']);

style.height=arForm['Alto'];
style.width=arForm['Ancho'];
style.backgroundColor=arForm['ColorFondo'];
style.position=arForm['Posicion'];
style.zIndex=arForm['z'];
style.top=arForm['y'];
style.left=arForm['x'];
style.padding=arForm['Padding'];
/*style.border="1px solid green";*/
}

if(sIdPadre==null)
{
ePadre.appendChild(this.eForm);
}
else
{
ePadre=document.getElementById(sIdPadre);
ePadre.appendChild(this.eForm);
}

//GETS
this.getID=function()
{
return this.eForm.id;
}
this.getWidth=function()
{
return this.eForm.offsetWidth;
}

this.getHeight=function()
{
return this.eForm.offsetHeight;
}

this.getTop=function()
{
return this.eForm.offsetTop;
}

this.getLeft=function()
{
return this.eForm.offsetLeft;
}

//SETS
this.setWidth=function(sValor)
{
this.eForm.style.width=sValor;
}

this.setHeight=function(sValor)
{
this.eForm.style.height=sValor;
}

this.setTop=function(sValor)
{
this.eForm.style.top=sValor;
}

this.setLeft=function(sValor)
{
this.eForm.style.left=sValor;
}
}

//CLASE INPUT boton, texto, hidden submit..
function CInput(arInput, eParent)
{
var ePadre=document.body;
this.eInput=document.createElement('input');

with(this.eInput)
{
setAttribute("type", arInput['Tipo']);
id=arInput['id'];
setAttribute("name", arInput['Nombre']);
setAttribute("value", arInput['Valor']);
//Estilo
style.width=arInput['Ancho'];
}

if(arInput['Tipo']=="button")
{
//Registramos los eventos
//http://www.w3.org/TR/DOM-Level-2-Events/events.html
if(document.all) //ES IE
{
this.eInput.attachEvent("onclick", pCancelar);
}
else //OTROS NAVEGADORES
{
this.eInput.addEventListener("click", pCancelar, true);
}
}


function pCancelar()
{
var eDivAux = document.getElementById(eGDivForm.getID());
document.body.removeChild(eDivAux);

eDivAux = document.getElementById(eGDivFondo.getID());
document.body.removeChild(eDivAux);

//Destruyo mis objetos
oGVentana=null;
eGDivFondo=null;
eGDivForm=null;
eGFormulario=null;
eGTabla=null;
eGHidFila=null;
eGTxtConcep=null;
eGTxtCant=null;
eGbotCancelar=null;
eGSubAceptar=null;

//Actualizo mi variable
bGFrmCreado=false;
}

if(eParent==null)
{
ePadre.appendChild(this.eInput);
}
else
{
eParent.appendChild(this.eInput);
}

//GETS
this.getID=function()
{
return this.eInput.id;
}

this.getValor=function()
{
return this.eInput.value;
}

this.getWidth=function()
{
return this.eInput.offsetWidth;
}

//SETS
this.setWidth=function(sValor)
{
this.eInput.style.width=sValor;
}
}

//CLASE TABLA
function CTabla(arTabla, sIdPadre)
{
var arTextos=new Array();
arTextos[0]="F";
arTextos[1]="CONCEPTO";
arTextos[2]="CANTIDAD";
arTextos[3]="";
arTextos[4]="";

var ePadre=document.body;
this.eTable=document.createElement('table');

with(this.eTable)
{
id=arTabla['id'];
setAttribute("name", arTabla['Nombre']);

style.height=arTabla['Alto'];
style.width=arTabla['Ancho'];
style.backgroundColor=arTabla['ColorFondo'];
style.position=arTabla['Posicion'];
style.zIndex=arTabla['z'];
style.top=arTabla['y'];
style.left=arTabla['x'];
style.padding=arTabla['Padding'];
style.border=arTabla['Borde'];
}
//Genero la tabla
for(var i=0; i<arTabla['Filas']; i++)
{
var auxTR=document.createElement("tr");
for(var j=0; j&ltarTabla['Columnas']; j++)
{
var auxTD=document.createElement("td");
var auxText;
if(i==0) //Es la cabecera
{
auxText=document.createTextNode(arTextos[j]);
auxTD.appendChild(auxText);
}
else //El resto de filas
{
switch (j)
{
case 0:
eGHidFila = new CInput(arHIDDEN, auxTD);
auxText=document.createTextNode(eGHidFila.getValor());
auxTD.appendChild(auxText);
break
case 1:
eGTxtConcep = new CInput(arTXTCONCEP, auxTD);
break
case 2:
eGTxtCant = new CInput(arTXTCANT, auxTD);
break
case 3:
eGSubAceptar = new CInput(arSUBACEPTAR, auxTD);
break
case 4:
eGbotCancelar = new CInput(arBOTCANCELAR, auxTD);
break
default:
document.write("Esta columna no existe!!");
}
}
auxTR.appendChild(auxTD);
}
this.eTable.appendChild(auxTR);
}

if(sIdPadre==null)
{
ePadre.appendChild(this.eTable);
}
else
{
ePadre=document.getElementById(sIdPadre);
ePadre.appendChild(this.eTable);
}

//GETS
this.getID=function()
{
return this.eTable.id;
}
this.getWidth=function()
{
return this.eTable.offsetWidth;
}

this.getHeight=function()
{
return this.eTable.offsetHeight;
}

this.getTop=function()
{
return this.eTable.offsetTop;
}

this.getLeft=function()
{
return this.eTable.offsetLeft;
}

//SETS
this.setWidth=function(sValor)
{
this.eTable.style.width=sValor;
}

this.setHeight=function(sValor)
{
this.eTable.style.height=sValor;
}

this.setTop=function(sValor)
{
this.eTable.style.top=sValor;
}

this.setLeft=function(sValor)
{
this.eTable.style.left=sValor;
}
}

//Procedimiento que vincularas a un evento Click y que dara como resultado
//la generacion del formulario
function pClick()
{
//Objeto ventana obtiene el tamaño de la pantalla
//necesario para el centrado y el recubrimiento de los controles
oGVentana = new CVentana();

//El elemento Div con opacidad
eGDivFondo= new CDiv(arDIVFONDO,null);
eGDivFondo.setWidth(oGVentana.getAncho());
eGDivFondo.setHeight(oGVentana.getAlto());

//El elemento Div contenedor del formulario
eGDivForm = new CDiv(arDIVFORM, null);

//Centro el contenedor en pantalla
var aux=(eGDivFondo.getWidth()-eGDivForm.getWidth())/2 + "px";
eGDivForm.setLeft(aux);
aux=(eGDivFondo.getHeight()-eGDivForm.getHeight())/2 + "px";
eGDivForm.setTop(aux);

//Creo el Formulario y lo adjunto a su padre el eGDivForm
eGFormulario=new CForm(arFORM, eGDivForm.getID());

//Creo la Tabla (para tabular mis controles) y lo adjunto a su padre eGFormulario
eGTabla=new CTabla(arTABLA, eGFormulario.getID());

//Indico que se ha generado el formulario, esto me servira para
//el evento que se ejecuta cuando se redimensiona la pantalla
bGFrmCreado=true;
}

window.onresize = function ()
{
if(bGFrmCreado)
{
//Creo nuevamente oVentana para actualizar su tamaño
oGVentana = new CVentana();
//Redimensiono el Div con opacidad
eGDivFondo.setWidth(oGVentana.getAncho());
eGDivFondo.setHeight(oGVentana.getAlto());

//centro divForm
var aux=(eGDivFondo.getWidth()-eGDivForm.getWidth())/2 + "px";
eGDivForm.setLeft(aux);
aux=(eGDivFondo.getHeight()-eGDivForm.getHeight())/2 + "px";
eGDivForm.setTop(aux);
}
}




Archivo prueba.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script type="text/javascript" src="CSS_JS/jsFormDinamico.js"></script>
<title>Formulario Dinamico</title>
</head>
<body id="cuerpo">
<div id="divFormulario">
<form id="frmPagina" method="" action="">
<fieldset>
<dl>
<dt></dt>
<dd><input type="button" id="botCrear" name="botCrear" value="Crear Formulario" onclick="pClick();" /></dd>
</dl>
</fieldset>
</form>
</div>
</body>
</html>