lunes, 8 de marzo de 2010

Clase de abstracción de datos para PHP-MySQL (Entidades/Business Objects)

Cuando trabajamos en PHP muchas veces tenemos tareas repetitivas de para crear inserts, updates y cualquier cantidad consultas a la base de datos. Si mejoramos el método podemos encapsular clases que abstraen las tablas en la base de datos y las llamamos "Entidades" o "Business Objects". Por ejemplo si tenemos una tabla "empleados" podriamos crear la entidad "class Empleado" el cual encapsula métodos Read y Save para guardar registros de empleados en particular, junto a todos los métodos que acompañan la clase.

Para automatizar el proceso de crear entidades en PHP, he creado una clase llamada genericDB, que se encarga de crear métodos set, get, getId, setId para cualquier tabla que tenga un id autonumérico (como primary key).

Podriamos ejemplificar su uso suponiendo que tenemos una tabla llamda "empleados" con un id_empleado autonumerico como clave primaria. El código para utilizar la tabla empleado (como entidad) quedaría asi:

<?php

//* Para leer un registro
$miempleado = new GenericDB("empleados");
$miempleado->setId(5);
if(
$miempleado->Read()) {
echo(
"El empleado existe<br>");
echo(
"El nombre del empleado es ".$miempleado->get("nombre"))
}


//* Para modificar un registro:
$miempleado = new GenericDB("empleados");
$miempleado->setId(5);
if(
$miempleado->Read()) {
echo(
"El empleado existe<br>");
echo(
"El nombre del empleado es ".$miempleado->get("nombre")."<br>")
echo(
"modificamos el nombre<br>");
$miempleado->set("nombre","Pedro");
if(
$miempleado->Save()) {
echo(
"El empleado se ha salvado como ".$miempleado->get("nombre"));
}
}

// Para crear un nuevo registro (nombre, apellido y cedula son campos en la tabla empleados):

$miempleado = new GenericDB("empleados");
$miempleado->set("nombre","Carlos Alberto");
$miempleado->set("apellido","Perez");
$miempleado->set("cedula","12346334");
if(
$miempleado->Save()) {
echo(
"Enhorabuena, se ha creado un nuevo registro <br>");
echo(
"El id del nuevo registro es ".$miempleado->getId()."<br>");
} else {
echo(
"error: ".$miempleado->_message);
}

?>
Puedes bajar el código de la clase genericDb haciendo click aqui.

Autologin en SSH con Putty

Una vez intenté establecer conexiones automáticas mediante SSH a través de putty, generando las llaves, colocandolas en el servidor y de repente: sorpresa!... un mensaje que dice "Server Refuse Our Key". Así que me puse a investigar un poco sobre el tema y encontré la solución. Aqui describo los pasos:

1. Descargar Putty y Puttygen (buscar en google)
2. Abrir Puttygen y generar la llave moviendo el mouse en el recuadro del programa.
3. Salvar la llave publica y la llave privada (.ppk)
4. Colocar la llave publica al servidor donde nos queremos conectar.
5. Cambiamos el formato de la llave pública a openssh de esta manera:

ssh-keygen -if llavepublica > llavepublica_openssh

6. Creamos la carpeta .ssh y le asignamos permisologia adecuada.
mkdir .ssh
chmod 700 .ssh

7. copiamos el contenido de la llave publica en el archivo authorized_keys dentro de la carpeta .ssh
cat llavepublica_openssh >> .ssh/authorized_keys

8. Nos vamos a la seccion "Connection > Data " y en el cuadro autologin colocamos el usuario.

9. Abrimos el putty y nos vamos a la configuracion "Connection > SSH > Auth", alli le damos click al botón browse y seleccionamos la llave privada.

10. Salvamos la sesión con el nombre del servidor y LISTO!


Si queremos que inicie sesión automaticamente podemos crear un acceso directo en windows con el siguiente comando. (incluyendo las comillas)

putty.exe -load "misesion"

domingo, 14 de junio de 2009

Añadir subtitulos en películas Divx, MKV para verlas en el PS3.

Siempre nos preguntamos como poner subtitulos srt en peliculas DivX para verlos en el PS3 a través de un servidor multimedia o en un DVD de mesa con soporte para este tipo de peliculas. El problema radica en que los media servers no multiplexan el tiempo real los subtítulos SRT a menos que hagan Transcoding de los mismos (lo que consume mucho tiempo de procesamiento). Aqui les dejo una solución para pegar subtítulos en sus peliculas de la manera rápida (les tomará como 3 minutos por pelicula) y éstos serán seleccionables a través de las opciones del DVD, PS3 o cualquier hardware con logo de DivX.

1. Pegar subtitulos seleccionables a divX, Xvid

Para esto descargamos el AviAddXSub. Este programa nos permite unir subtitulos .srt a películas de formato DIVX o XVID. Una vez que lo tengamos ponemos la pelicula (peliculaejemplo.avi) junto a los subtitulos con exactamente el mismo nombre (peliculaejemplo.srt). Vamos a la pestaña de Configuracion, seleccionamos letra ARIAL con tamaño 22.

Volvemos a la pestaña "Create DivX with Subtitles" y abrimos la pelicula (File name), seleccionamos una carpeta de salida (output folder), hacemos click en el botón "Create Subtitled DivX File" y listo!.
El par de minutos tendremos un archivo .DIVX con subtitulos seleccionables. Este archivo es compatible con cualquier reproductor de software o hardware con el logo DivX.

2. Pegar subtitulos permanentes a peliculas matroska (.MKV) y hacerlas compatibles con PS3. (x264, bluray)

Primero que todo descargamos e instalamos el programa MKV2VOB.

Como en el caso anterior, juntamos en una misma carpeta la pelicula (peliculaejemplo.mkv) con su respectivo archivo de subtítulos (peliculaejemplo.srt) Abrimos el programa y nos vamos a la pestaña de configuración donde activaremos las siguientes opciones:

Always Encode Subtitles.
Load Subtitles from File.
Large Subtitles.

Volvemos a la pestaña (Add File) y seleccionamos nuestra pelicula con el boton de "Source File", también podemos opcionalmente especificar la carpeta de destino ("Destination Directory"). Una vez que la agregamos se empezará a realizar el transcoding de la película. El proceso tarda un poco mas pero tendremos una pelicula X264 totalmente compatible con consolas PS3 y subtítulos añadidos con la calidad original.

viernes, 24 de octubre de 2008

Detección de rostros en PHP con Facedetect y OpenCV

Con el auge de las tecnologías de detección de rostros de las camaras fotográficas, decidi investigar un poco al respecto y me topé con la biblioteca OpenCV (Open Computer Visión Library). Esta biblioteca permite hacer análisis y transformaciónes a videos e imágenes así como detección de formas usando inteligencia artificial. Logré compilar una extensión para reconocimiento de personas en PHP llamada Facedetect el cual contiene dos funciones disponibles para enlazarlas con PHP5:

face_count(): Devuelve el numero de rostros encontradas en la imagen.
face_detect(): Devuelve un array con las coordenadas de los rostros disponibles.


Imágen sin procesar

Después de procesar
Numero de personas en la foto: 10


Monté la plataforma utilizando un servidor Ubuntu Hardy Heron con Apache2 y php5.

script:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;" />
<title>Detector de Rostros</title>
</head>
<body>
<h1>Open Computer Vision - Contador de personas</h1>
<form action="<?=$_SERVER['PHP_SELF']?>" method="post" ENCTYPE="multipart/form-data">
Archivo<input type="file" name="file">
<input type="submit" value="subir">
<input type="hidden" name="uploadflag" value="1">
</form>
<br>
<?php
if($_POST['uploadflag']==1){
if(
$_FILES['file']['tmp_name'] != ""){
$imagenfinal = "imagenes/foto".date("Ymdhis").".jpg";
$cascade = "/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt.xml";
move_uploaded_file($_FILES['file']['tmp_name'],$imagenfinal);
$format = strtolower(substr(strrchr($imagenfinal,"."),1));
switch(
$format)
{
case
'gif' :
$type ="gif";
$img = imagecreatefromgif($imagenfinal);
break;
case
'png' :
$type ="png";
$img = imagecreatefrompng($imagenfinal);
break;
case
'jpg' :
$type ="jpg";
$img = imagecreatefromjpeg($imagenfinal);
break;
case
'jpeg' :
$type ="jpg";
$img = imagecreatefromjpeg($imagenfinal);
break;
default :
die (
"<br>ERROR: tipo de archivo desconocido: $imagenfinal");
break;
}
$total = face_count($imagenfinal, $cascade);
$faces = face_detect($imagenfinal ,$cascade);

echo
"Numero de personas en la foto: ".$total;
$color = imagecolorallocate($img, 132, 135, 28);
for(
$i=0; $i<$total; $i++) {
$face = $faces[$i];
$x1 = $face['x'];
$y1 = $face['y'];
$x2 = $x1+$face['w'];
$y2 = $y1+$face['h'];
imagerectangle($img, $x1, $y1, $x2, $y2, $color);
echo(
"<br>persona ".($i+1)." : ($x1,$y1) - ($x2,$y2)");
}

if(
$total>0) {
$dest = "imagenes/nuevafoto_".date("Ymdhis").".jpg";
if(
$type=="gif") imagegif($img, $dest);
if(
$type=="jpg") imagejpeg($img, $dest);
if(
$type=="png") imagepng($img, $dest);
if(
$type=="bmp") imagewbmp($img, $dest);
echo
'<br><img src="'.$dest.'"><br>';
}
echo
'<a href="'.$_SERVER['PHP_SELF'].'"></a>';
} else{ echo
"<br>Debe subir una imagen<br>"; }
echo
'<br><br><a href="'.$_SERVER['PHP_SELF'].'">Recargar</a>';
}
?>
</body>
</html>

domingo, 15 de junio de 2008

Cheat para Word Challenge en Facebook

Aqui les dejo un bot generado en php para el famoso juego de facebook "Word Challenge". El programa genera un script en Windows Scripting Tool (vbs) que juega por ti.

"miscript.vbs"; // archivo de salida
$retardoinicial = 1800; // tiempo inicial de espera (en milisegundos) para hacer foco en la ventana del juego
$retardotecla = 0; //milisegundos
$diccionario = "xxxxxxxxxx"; // aqui va la pagina donde se obtienen las palabras
// esta pagina del diccionario deberan solicitármela por correo

function OutputFile($file) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; '
.'filename="'.$file.'"');
echo
file_get_contents($file);
}

function
SaveContent($content, $file)
{
if (
file_exists($file)) @unlink($file);
if (!
$handle = fopen($file, 'w')) die("Error in $file");
fwrite($handle,$content);
fclose($handle);
}

function ParseContent($string){
preg_match_all("(word=[a-zA-Z]{3}[a-zA-Z]*)", $string, $matches);
$rightwords = array();
foreach(
$matches[0] as $valor) $rightwords[] = substr($valor,5);
$rightwords = array_reverse(array_unique($rightwords));
return $rightwords;
}

if (
$_POST) {
srand((float)microtime() * 1000000);
$url = "http://$diccionario?letters=".substr($_POST['letras'],0,6).
"&dict=sowpods&Cheat=Cheat"
;
$input = @file_get_contents($url) or die('Cant access $url');
$rightwords = ParseContent($input);
$content = 'Dim Wsh'."\r\n";
$content.= 'Set Wsh = Wscript.CreateObject("Wscript.Shell")'."\r\n";
$content.= 'Wsh.AppActivate "Exploring"'."\r\n";
$content.= 'Wscript.sleep('.$retardoinicial.')'."\r\n";
foreach(
$rightwords as $word) {
$scriptline = '';
for(
$i=0; $i<strlen($word); $i++)
{
$letter = substr($word,$i,1);
$scriptline.='Wsh.SendKeys "{'.$letter.'}"'."\r\n";
}
$scriptline.='Wsh.SendKeys "{ENTER}"'."\r\n";
$content.=$scriptline;
}
SaveContent($content,"./".$scriptname);
OutputFile($scriptname);
exit();
}

?>
<html>
<body>
<h3>Generador de palabras para Word Challenge</h3>
<form name="miforma" method="post" action="<?=$_SERVER['PHP_SELF']?>">
<label>letras</label>
<input type="text" name="letras" />
<input type="submit" name="submit" value="submit">
<br>
</form>
</body>
</html>


miércoles, 5 de septiembre de 2007

Progress Bar en ASP.NET 2.0

Buscando Barras de progreso en Internet me topé con uno de esos controles dll que funcionaba a la perfección, pero pedia un donativo (practicamente shareware con alerta y todo) para el control. Asi que decidí ver como funcionaba y publicar mi propio control para uso público. Aqui les dejo el código fuente (ProgressBar.ascx y ProgressBar.ascx.vb)

ProgressBar.ascx

<% Control Language="VB" AutoEventWireup="false" CodeFile="ProgressBar.ascx.vb" Inherits="componentes_ProgressBar" %>
<table cellspacing="1" cellpadding="0" border="0" style="border-color:Blue;border-width:1px;border-style:solid;height:20px;width:200px;"><tr><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#0000ff;"></td><td style="background-color:#d3d3d3;"></td><td style="background-color:#d3d3d3;"></td><td style="background-color:#d3d3d3;"></td><td style="background-color:#d3d3d3;"></td><td style="background-color:#d3d3d3;"></td><td style="background-color:#d3d3d3;"></td><td style="background-color:#d3d3d3;"></td></tr></table>



ProgressBar.ascx.vb

Partial Class componentes_ProgressBar : Inherits System.Web.UI.UserControl
Private _forecolor As Color = Color.Blue
Private _backgroundcolor As Color = Color.LightGray
Private _width As String = "200px"
Private _valor As Integer = 0
Private _maxCuadros As Integer = 30

Public Property ForeColor() As Color
Get
Return
_forecolor
End Get
Set
(ByVal value As Color)
Me._forecolor = value
End Set
End Property

Public Property
BackgroundColor() As Color
Get
Return
_backgroundcolor
End Get
Set
(ByVal value As Color)
Me._backgroundcolor = value
End Set
End Property

Public Property
MaxCuadros() As Integer
Get
Return
_maxCuadros
End Get
Set
(ByVal value As Integer)
_maxCuadros
= value
End Set
End Property

Public Property
Width() As String
Get
Return
_width
End Get
Set
(ByVal value As String)
_width
= value
End Set
End Property

Function
ToHexColor(ByVal c As Color) As String
Return
"#" + c.ToArgb().ToString("x").Substring(2)
End Function

Public Property
Value() As Integer
Get
Return
_valor
End Get
Set
(ByVal value As Integer)
If value > 100 Then value = 100
If value < 0 Then value = 0
_valor = value
End Set
End Property

Protected Overrides Sub
Render(ByVal Output As HtmlTextWriter)
Dim i As Integer
Dim
vreal As Integer = CInt((_valor * _maxCuadros / 100) + 0.5)
Dim fcolor As String = ToHexColor(_forecolor)
Dim bcolor As String = ToHexColor(_backgroundcolor)
Dim c As String
Output.Write("<table cellspacing=""1"" cellpadding=""0"" border=""0"" style=""border-color:Blue;border-width:1px;border-style:solid;height:20px;width:" & _width & ";""><tr>")
For i = 1 To _maxCuadros
c
= IIf(vreal < i, bcolor, fcolor)
Output.Write(
"<td style=""background-color:" & c & ";""></td>")
Next
Output.Write("</tr></table>")
End Sub
End Class



domingo, 2 de septiembre de 2007

Selección múltiple con checkbox en Gridview

Muchas veces necesitamos ejecutar una acción para múltiples filas seleccionadas en un gridview a través de un checkbox, para ello lo primero que necesitamos es agregar la propiedad DataKeyNames con el ID primario de los datos que cargamos, asi podemos realizar las acciones necesarias accediendo individualmente a cada registro del GridView.

<asp:GridView id="gridview1" runat="server" DataKeyNames="id_persona" AutoGenerateColumns="False">
<Columns>
.
.

Aqui agregamos el TemplateField con el checkBox para insertarlo en el GridView...

.
.
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox id="chkMarca" runat="server"></asp:CheckBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>

Si queremos que las acciones se tomen sin necesidad de utilizar los eventos manejados por el GridView, podemos crear un Método que puede ser llamado directamente por un botón u otro control.


Private Sub EliminarPersonasSeleccionadas()
Dim persona as New Persona()
Dim iditem As Integer
For Each
dgi As GridViewRow In Me.gridview1.Rows
Dim ch As CheckBox = CType(dgi.FindControl("chkMarca"), CheckBox)
If ch.Checked Then
iditem = gridview1.DataKeys(dgi.DataItemIndex).Value
persona.id_persona
= iditem
persona.Eliminar()
End If
Next
End Sub