Wednesday, November 28, 2007

Store and saving binary data (images, coding, etc.) into MySql Database with PHP

An interesting topic in Mysql is to use the database to store binary data, such as images or html code. The first step is to create the database:

CREATE TABLE binary_data (
id INT(4) NOT NULL AUTO_INCREMENT PRIMARY KEY,
descripction CHAR(50),
bin_data LONGBLOB,
filename CHAR(50),
filesize CHAR(50),
filetype CHAR(50)
);


The following script can be used to insert binary objects in the database from a browser. Note that the tag is used input type = "file" a form html to upload a file.


<HTML>
<HEAD><TITLE>Store and saving binary data (images, coding,
etc.) into MySql Database with PHP
</TITLE></HEAD>
<BODY>
<?php
if ($submit) {
//
Code that runs if I press the submit button
MYSQL_CONNECT( "localhost", "root", "password");
mysql_select_db( "binary_data");
$data = addslashes(fread(fopen($form_data, "r"),
filesize($form_data)));
$result=MYSQL_QUERY( "INSERT INTO binary_data(description,
bin_data,filename,filesize,filetype) ". "VALUES
('$form_description','$data',
'$form_data_name',
'$form_data_size','$form_data_type')");
$id= mysql_insert_id();
print "<p>Database ID: <b>$id</b>";
MYSQL_CLOSE();
} else {
// else
bring up the form for new data:
?>
<form method="post" action=" <?php echo $PHP_SELF; ?>"
enctype="multipart/form-data">
File Description:<br>
<input type="text" name="form_description" size="40">
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="1000000">
<br>
Upload file to the database:<br>
<input type="file" name="form_data" size="40">
<p><input type="submit" name="submit" value="submit">
</form>
<?php
}
?>
</BODY>
</HTML>

Note the use of $ PHP_SELF predefined variable that contains the name of the script. This form is called himself regardless of the name that comes to the file.

The following script (getdata.php) can be used to recover data from the database, noting that the script expects to receive the variable $ id with id register to recover from the table.

<?php
if($id) {
@MYSQL_CONNECT( "localhost", "root", "contraseña");
@mysql_select_db( "binary_data");
$query = "select bin_data,filetype from binary_data where id=$id";
$result = @MYSQL_QUERY($query);
$data = @MYSQL_RESULT($result,0, "bin_data");
$type = @MYSQL_RESULT($result,0, "filetype");
Header( "Content-type: $type");
echo $data;
};
?>

To use an image that is obtained from the database can be used:


<img src="getdata.php?id=3">

Note as he passes the variable id to script to know what is the record to retrieve the base.



Almacenamiento de objetos binarios (imagenes, codigo, etc.) en MySQL desde PHP

Un tema interesante en Mysql es usar la base de datos para guardar además de datos de tipo texto datos binarios como por ejemplo código html o imágenes.
El primer paso es crear la base de datos:

CREATE TABLE binary_data (
id INT(4) NOT NULL AUTO_INCREMENT PRIMARY KEY,
descripction CHAR(50),
bin_data LONGBLOB,
filename CHAR(50),
filesize CHAR(50),
filetype CHAR(50)
);

El siguiente script puede usarse para insertar objetos binarios en la base de datos desde un browser. Notar que se usa el tag input type=”file” de un form html para subir un archivo.


<HTML>
<HEAD><TITLE>Almacenamiento de datos binarios en una base
de datos MySql</TITLE></HEAD>
<BODY>
<?php
if ($submit) {
//codigo que se ejecuta si se presiono el botón submit
MYSQL_CONNECT( "localhost", "root", "contraseña");
mysql_select_db( "binary_data");
$data = addslashes(fread(fopen($form_data, "r"),
filesize($form_data)));
$result=MYSQL_QUERY( "INSERT INTO binary_data(description,
bin_data,filename,filesize,filetype) ". "VALUES
('$form_description','$data',
'$form_data_name',
'$form_data_size','$form_data_type')");
$id= mysql_insert_id();
print "<p>Database ID: <b>$id</b>";
MYSQL_CLOSE();
} else {
// sino mostrar el formulario para nuevos datos:
?>
<form method="post" action=" <?php echo $PHP_SELF; ?>"
enctype="multipart/form-data">
File Description:<br>
<input type="text" name="form_description" size="40">
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="1000000">
<br>Cargar archivo en base de datos:<br>
<input type="file" name="form_data" size="40">
<p><input type="submit" name="submit" value="submit">
</form>
<?php
}
?>
</BODY>
</HTML>

Notar el uso de la variable predefinida $PHP_SELF que tiene el nombre del script de esta forma el formulario se llama a si mismo independientemente del nombre que se le ponga al archivo.

El siguiente script (getdata.php) puede usarse para recuperar los datos desde la base de datos, notar que el script espera recibir la variable $id con el id del registro a recuperar de la tabla.

<?php
if($id) {
@MYSQL_CONNECT( "localhost", "root", "contraseña");
@mysql_select_db( "binary_data");
$query = "select bin_data,filetype from binary_data where id=$id";
$result = @MYSQL_QUERY($query);
$data = @MYSQL_RESULT($result,0, "bin_data");
$type = @MYSQL_RESULT($result,0, "filetype");
Header( "Content-type: $type");
echo $data;
};
?>

Para usar una imagen que se obtiene de la base de datos se puede usar:


<img src="getdata.php?id=3">

Notar como se le pasa la variable id al script para saber cual es el registro a recuperar de la base.



Saturday, November 24, 2007

Capítulo 17: Manejo de Mail en PHP

Conexión a un server IMAP o POP3:

mail_handler=imap_open(string_mbox,user,password);

Donde mbox es de la forma:
{IP:PORT}MailBox

Ejemplos:

$mail=imap_open(“{190.190.190.190:143}INBOX”,”user”,”pass”);

Conexión a la carpeta INBOX de un servidor IMAP (puerto 143)

$mail=imap_open(“{190.190.190.190:110}”,”user”,”pass”);

Conexión a la carpeta raíz de un servidor POP3 (puerto 110)

Una vez establecida la conexión la función devuelve un handler que se utiliza en el resto de las funciones para acceder a las carpetas y mails dentro de las mismas.

Ejemplo:

$mbox = imap_open ("{your.imap.host:143}", "username", "password");
echo "

Mailboxes

\n";
$folders = imap_listmailbox ($mbox, "{your.imap.host:143}", "*");
if ($folders == false) {
echo "Call failed
\n";
} else {
while (list ($key, $val) = each ($folders)) {
echo $val."
\n";
}
}
echo "

Headers in INBOX

\n";
$headers = imap_headers ($mbox);
if ($headers == false) {
echo "Call failed
\n";
} else {
while (list ($key,$val) = each ($headers)) {
echo $val."
\n";
}
}
imap_close($mbox);

Una vez terminada la conexión se usa:

imap_close(mail_handler);

Manejo de MailBoxes:

int=imap_createmailbox (mail_handler string_mbox)

String mbox debe estar codificado con imap_utf7_encode() y el formato del string es el mismo que en imap_open.

Ejemplo:

$mbox = imap_open("{your.imap.host}","username","password",OP_HALFOPEN)
|| die("can't connect: ".imap_last_error());
$name1 = "phpnewbox";
$name2 = imap_utf7_encode("phpnewböx");
$newname = $name1;
echo "Newname will be '$name1'
\n";
# we will now create a new mailbox "phptestbox" in your inbox folder,
# check its status after creation and finaly remove it to restore
# your inbox to its initial state
if(@imap_createmailbox($mbox,imap_utf7_encode("{your.imap.host}INBOX.$newname"))) {
$status = @imap_status($mbox,"{your.imap.host}INBOX.$newname",SA_ALL);
if($status) {
print("your new mailbox '$name1' has the following status:
\n");
print("Messages: ". $status->messages )."
\n";
print("Recent: ". $status->recent )."
\n";
print("Unseen: ". $status->unseen )."
\n";
print("UIDnext: ". $status->uidnext )."
\n";
print("UIDvalidity:". $status->uidvalidity)."
\n";

if(imap_renamemailbox($mbox,"{your.imap.host}INBOX.$newname","{your.imap.host}INBOX.$name2")) {
echo "renamed new mailbox from '$name1' to '$name2'
\n";
$newname=$name2;
} else {
print "imap_renamemailbox on new mailbox failed: ".imap_last_error()."
\n";
}
} else {
print "imap_status on new mailbox failed: ".imap_last_error()."
\n";
}
if(@imap_deletemailbox($mbox,"{your.imap.host}INBOX.$newname")) {
print "new mailbox removed to restore initial state
\n";
} else {
print "imap_deletemailbox on new mailbox failed:
".implode("
\n",imap_errors())."
\n";
}
} else {
print "could not create new mailbox: ".implode("
\n",imap_errors())."
\n";
}
imap_close($mbox);

Devuelve true si pudo crear el mailbox o false en caso contrario.

int=imap_deletemailbox (mail_handler, string_mbox);

Elimina el mailbox indicado, el formato de mbox es el mismo que en imap_open.

int=imap_renamemailbox (mail_handler, string_old_mbox, string_new_mbox)

Permite renombrar un mailbox, el nombre del mailbox debe estar en el mismo formato que en imap_open.

obj_array=imap_getmailboxes (mail_stream, string_ref, string_pattern)

Devuelve un vector de objetos con información sobre los mailboxes

Los objetos que se encuentran en el vector tienen seteados los siguientes data_members:

· name – Nombre del mailbox (completo) encodeado, decodificar con imap_utf7_decode()
· delimiter – Delimitador usado para separar la jerarquía de mailboxes
· attributes – Es un bitmask que puede compararse con:
- LATT_NOINFERIORS (el mailbox no tiene subcarpetas)
- LATT_NOSELECT (es un mailbox no seleccionable)
- LATT_MARKED (mailbox marcado)
- LATT_UNMARKED (mailbox no marcado)

Ejemplo:

$mbox = imap_open("{your.imap.host}","username","password")
|| die("can't connect: ".imap_last_error());
$list = imap_getmailboxes($mbox,"{your.imap.host}","*");
if(is_array($list)) {
reset($list);
while (list($key, $val) = each($list))
{
print "($key) ";
print imap_utf7_decode($val->name).",";
print "'".$val->delimiter."',";
print $val->attributes."
\n";
}
} else
print "imap_getmailboxes failed: ".imap_last_error()."\n";
imap_close($mbox);
object=imap_status (mail_handler, string_mailbox, SA_ALL)

SA_ALL es una constante para recuperar toda la información sobre el mailbox, devuelve un objeto con los siguientes data members seteados:

· messages – número de mensajes en el mailbox
· recent – número de mensajes recientes en el mailbox
· unseen – número de mensajes no vistos en el mailbox

Ejemplo:

$mbox = imap_open("{your.imap.host}","username","password",OP_HALFOPEN)
|| die("can't connect: ".imap_last_error());
$status = imap_status($mbox,"{your.imap.host}INBOX",SA_ALL);
if($status) {
print("Messages: ". $status->messages )."
\n";
print("Recent: ". $status->recent )."
\n";
print("Unseen: ". $status->unseen )."
\n";
print("UIDnext: ". $status->uidnext )."
\n";
print("UIDvalidity:". $status->uidvalidity)."
\n";
} else
print "imap_status failed: ".imap_lasterror()."\n";
imap_close($mbox);

int imap_num_msg (mail_handler)

Devuelve el número de mensajes en el mailbox actual. (El abierto por el mail_handler)

int imap_num_recent (mail_handler)

Devuelve el número de mensajes recientes del mailbox correspondiente a mail_handler.

Manejo de mensajes:

object=imap_fetchstructure (mail_handler, int msg_number)

Devuelve un objeto con la estructura del mensaje recuperado:

Table 1. Returned Objects for imap_fetchstructure()

type Primary body type
encoding Body transfer encoding
ifsubtype True if there is a subtype string
subtype MIME subtype
ifdescription True if there is a description string
description Content description string
ifid True if there is an identification string
id Identification string
lines Number of lines
bytes Number of bytes
ifdisposition True if there is a disposition string
disposition Disposition string
ifdparameters True if the dparameters array exists
dparameters Disposition parameter array
ifparameters True if the parameters array exists
parameters MIME parameters array
parts Array of objects describing each message part

Cuando el mensaje es multipart “parts” es un vector donde cada elemento es un objeto con los siguientes datamembers:

· type
· encoding
· subtype
· description
· lines
· disposition

Luego según el trasnfer encoding (ver tabla 3) se puede usar la función de decodificación apropiada

Table 2. Primary body type

0 text
1 multipart
2 message
3 application
4 audio
5 image
6 video
7 other

Table 3. Transfer encodings

0 7BIT
1 8BIT
2 BINARY
3 BASE64
4 QUOTED-PRINTABLE
5 OTHER

Las funciones de decodificación provistas son:

string=imap_base64(string) convierte de base 64 a 8 bits
string=imap_8bit(string) convierte de 8 bits a quoted printable
string=imap_utf7_decode(string) convierte de 7 bits a 8 bits
string=imap_qprint(string) convierte de quoted printable a 8 bits
string=imap_binary(string) convierte de 8 bits a base64

El formato de salida “string” es 8 bits, si el formato de encoding es otro basta con usar la función apropiada.

string=imap_fetchbody (mail_handler, int msg_number, string part_number )

Recupera la parte indicada del body de un determinado mensaje. No realiza ningún tipo de decodificación.

array= imap_headers (mail_handlers)

Devuelve un vector de headers para el mailbox actual (cada header es un string y es un elemento del vector)

object=imap_rfc822_parse_headers(string headers)

Parsea un header de acuerdo a rfc822, devuelve un objeto con los siguientes data_members:

· remail
· date
· Date
· subject
· Subject
· in_reply_to
· message_id
· newsgroups
· followup_to
· references

string imap_body (mail_handler, int msg_number)

Devuelve el body de un determinado mensaje.

Envío de mail:

Enviar mail desde PHP es sencillo con la función:

bool= mail (string to, string subject, string message [, string additional_headers])

Ejemplo

mail("rasmus@lerdorf.on.ca", "My Subject", "Line 1\nLine 2\nLine 3");

Ejemplo 2. Envio de mail con encabezado.

mail("nobody@aol.com", "the subject", $message,
"From: webmaster@$SERVER_NAME\nReply-To: webmaster@$SERVER_NAME\nXMailer:
PHP/" . phpversion());

Capítulo 18: Networking y FTP usando PHP

Funciones de FTP:

Uno de los problemas no solucionados por la mayoría de los lenguajes de scripting para la web es la transferencia de archivos entre diversos sites, usando NFS (Network file system) es posible crear zonas de un file-system que sean compartidas por más de un site, pero esto obliga a usar NFS, a tener una sobrecarga administrativa y además insertar varios problemas de seguridad delicados relacionados con NFS. El método más seguro y confiable para transferir archivos, PHP provee funciones nativas para usar FTP en forma directa desde un script php, las funciones más usadas son las siguientes:

ftp_handler=ftp_connect(host);

Ejemplo

$ftp=ftp_connect(“100.100.100.100”);

Si el puerto de FTP no es el default (21) se puede pasar como segundo parámetro de ftp_connect, la función devuelve un handler a ser usado por el resto de las funciones de FTP.
Devuelve true/false segun el éxito o fracaso de la conexión.

int=ftp_login(ftp_handler,string_user,string_password);

Realiza un login a la conexión FTP indicada por el handler. (devuelve true/false según el éxito o fracaso del login)

int=ftp_chdir(ftp_handler, string_directory);

Cambia al directorio especificado como segundo parámetro dentro de la conexión ftp abierta para el ftp_handler pasado.Devuelve true/false

int=ftp_get (ftp_handler, string_local_file, string_remote_file, int mode);

Transfiere el archivo string_remote_file a la maquina donde corre el script creandolo con el path indicado en string_local_file, el modo debe ser una constante que puede ser FTP_BINARY o FTP_ASCII

Ejemplo

$ret=ftp_get($ftp,”/temp/cosa.dat”,”cosa.dat”,FTP_BINARY);

Notar que no deben usarse comillas en el cuarto parámetro por tratarse de una constante y no de un string.

int=ftp_fget (ftp_handler, file_handler, string_remote_file, int mode)

Idem anterior pero el segundo parámetro es un handler a un archivo abierto con fopen en donde se guardaran los datos leídos desde la conexión ftp.

int=ftp_put (ftp_handler, string_remote_file, string_local_file, int mode)

Transfiere un archivo local indicado por string_local_file mediante la conexión ftp abierta creando un archivo de nombre string_remote_file.

int=ftp_fput (ftp_handler, string_remote_file, file_handler, int mode)

Idem anterior pero el archivo a trasnferir se indica por el file_handler de un archivo abierto con fopen.

string=ftp_mkdir (ftp_handler, string_directory)

Crea un directorio en la conexión ftp abierta, devuelve el nombre del directorio creado o falso si no pudo crearlo.

int=ftp_rmdir (ftp_handler, string directory)

Elimina el directorio indicado, devuelve true/false.

int=ftp_cdup (ftp_handler)

Cambia al directorio padre del actual.

array=ftp_rawlist (ftp_handler, string_directory)

Devuelve un vector con la lista de archivos presentes en el directorio indicado de acuerdo al comando FTP ftp_list, el resultado es un vector donde cada elemento del vector es una línea devuelta por ftp_list.

int=ftp_size (ftp_handler, string_remote_file)

Devuelve el tamaño del archivo indicado.

ftp_quit(ftp_handler);

Se desconecta de la conexión ftp realizada con ftp_connect.

Networking en PHP:

PHP dispone de varias funciones de networking la más usada y la más flexible es fsockopen que permite conectarse a un socket en un host determinado por una dirección IP y un puerto, mediante esta funcion es posible conectarse a servidores HTPP, FTP, Telnet, IMAP, POP3 y otros protocolos.
Es de destacar que la funcionalidad de Networking de PHP es como CLIENTE, PHP no puede crear un socket con nombre y hacer un “listen” de conexiones a dicho port por lo que no puede funcionar como servidor. La sintaxis de fsockopen es:

file_handler=fsockopen (string_hostname, int port , int errno , string_errstr , double timeout)

Los tres últimos parámetros son opcionales.
Hostname es el nombre o dirección IP del host al cual conectarse.
Port es el número de puerto al cual conectarse en el host.
errno debe ser una referencia a una variable en donde se guarda el número de error en caso de no poder conectarse.
errstr es una referencia a una variable en donde se guarda un mensaje de error en caso de no poder conectarse
El timeout es el tiempo máximo a esperar por la conexión en segundos.
Devuelve un file handler o false según pueda o no conectarse. El file hanlder devuelto puede luego usarse como un archivo normal usando fgets, fputs, feof, fclose, etc...

Ejemplo:

$fp = fsockopen ("www.php.net", 80, &$errno, &$errstr, 30);
if (!$fp) {
echo "$errstr ($errno)
\n";
} else {
fputs ($fp, "GET / HTTP/1.0\n\n");
while (!feof($fp)) {
echo fgets ($fp,128);
}
fclose ($fp);
}

En este ejemplo abrimos el puerto 80 (Protocolo HTTP) de un host (www.php.net )
Luego ponemos en el socket un request de HTTP y entramos en un loop recuperando el contenido que devuelve el server. Es un mini simulador de browser HTTP.

Capítulo 19: Funciones adicionales de PHP

Persistencia:

Una de las características importantes en lenguajes orientados a objetos o lenguajes de scripting modernos es la persistencia, un objeto persistente es aquel que puede almacenarse en un medio de almacenamiento secundario (un archivo o una base de datos) para luego recuperarlo. PHP provee de dos funciones que permiten realizar esto serializando y des-serializando variables de PHP.

string=serialize(var);

Recibe cualquier variable de PHP incluso un objeto y devuelve un string que es una representación de la variable, dicho string puede almacenarse en un archivo o una base de datos para lograr persistencia.

var=unserialize(string);

Recibe un string que es la serialización de una variable, des-serializa y asigna a la variable pasada. Para desserializar un objeto es necesario que el script que usa unserialize disponga de la definición de la clase.

Funciones de hashing y encriptación:

string=md5(string)

Devuelve un string de 32 bytes que es un “digest” del string original, es decir aplica al string original una función de hashing unidireccional.

string=crypt(string)

Encripta un string usando el método unidireccional de Unix, usado por ejemplo para almacenar passwords, el string devuelto es de extensión variable. No se puede desencriptar.

Generación de identificadores únicos:

string=uniqid(string_base);

Construye un identificador único tomando como base un string pasado, por ejemplo para generar identificadores únicos de 32 bits aleatorios se usa:

$better_token = md5 (uniqid (rand()));

Ejecución de codigo PHP:

eval(string_codigo);

Evalúa el string como si fuera código PHP y lo ejecuta.

Ejemplo:

eval(“print(\”hola\”)”);

Imprime hola como si se ejecutara la instrucción print, la función eval es útil en varios casos por ejemplo para guardar código PHP en un archivo o base de datos y luego recuperarlo y ejecutarlo dinámicamente (por ejemplo para que usuarios de un web site suban sus propios scripts PHP) o bien usando funciones de parsing XML para insertar en XML processing-instructions de tipo y luego en el script php que parsea el XML ejecutar el código php con eval.

Control del script:

sleep(segundos);

Hace una pause de la cantidad de segundos indicados.

die(string);

Termina la ejecución del script imprimiendo el string pasado.

exit();

Finaliza la ejecución del script.

Manejo de URLs

string=base64_decode(string);

Decodifica un string encodeado en base64.

string=base64_encode(string);

Codifica un string a base64.

string=urlencode(string);

Codifica un string de acuerdo a RFC1738 es decir reemplaza todos los caracteres que no sean alfanuméricos o “_”,”.“,”-“ por un signo “%” seguido de una representación hexadecimal del caracter de acuerdo a RFC1738, los espacios en blanco se codifican como %20 por ejemplo. Este formato es “seguro” para pasarlo como query_string en un URL

Ejemplo tipico:

$ulr_string=urlencode($string_raro);
print(“”);
etc...

string=urldecode(string);

Decodifica un string encodeado con urlencode.

array=parse_url(string_url);

Recibe un string representando una URL y devuelve un vector asociativo de donde pueden recuperarse las sigiuientes claves: "scheme", "host", "port", "path", "query"

Ejemplo:

http://www.yahoo.com:8080/pruebas/coso.php?hola=5&cosa=6

Scheme : http
Host : www.yahoo.com
Port : 8080
Path : /pruebas/coso.php
Query : hola=5&cosa=6