miércoles, 19 de diciembre de 2012

Generar imágenes al vuelo con PHP

En esta ocasión vamos a ver un ejemplo muy simple para la generación de una imagen con formato PNG mediante algunas de las funciones que ofrece la biblioteca GD2.

Hemos utilizado imagepng() para generar al vuelo el archivo png, es decir, enviamos directamente la imagen al navegador, pero podríamos haber guardado la imagen en el disco simplemente añadiendo un segundo parámetro con su nombre.

//definimos el ancho y alto
$width = 200;
$height = 200;

//Creamos un lienzo sobre el que trabajar
$img = imagecreatetruecolor($width, $height) or die('No se pudo iniciar el flujo de la imagen');

//colores
$blanco = imagecolorallocate($img, 255, 255, 255);
$otro = imagecolorallocate($img, 130, 205, 242);
$azul = imagecolorallocate($img, 0, 0, 64);

//dibujar la imagen
imagefill($img, 0, 0, $azul);
imageline($img, 0, 0, $width, $height, $blanco);
imagefilledrectangle($img, 0, 0, 100, 100, $otro);
imagestring($img, 4, 40, 145, 'Un texto', $blanco);
imagestring($img, 4, 110, 50,  'Otro Texto', $blanco);

//ofrecer el resultado
header('Content-type: image/png');
imagepng($img);

//liberar recursos
imagedestroy($img);

Ahora vamos a escribir un texto centrado sobre una imagen jpg ya existente, para ello necesitamos obtener las dimensiones de la imagen y también del texto para poder ubicarlo correctamente.

$texto = 'un texto centrado';
$tamano_texto = 20;
$fuente = $_SERVER['DOCUMENT_ROOT'] . '/site/arial.ttf';

$img = imagecreatefromjpeg('iron-maiden.jpg');
$ancho = imagesx($img);
$alto = imagesy($img);

$caja_texto = imagettfbbox($tamano_texto, 0, $fuente, $texto);

$ancho_texto = $caja_texto[2] - $caja_texto[0];
$alto_texto = abs($caja_texto[7] - $caja_texto[1]);

$posicion_texto_x = ($ancho/2.0) - ($ancho_texto/2.0);
$posicion_texto_y = ($alto/2.0) - ($alto_texto/2.0);

$blanco = imagecolorallocate($img, 255, 255, 255);

imagettftext($img, $tamano_texto, 0, $posicion_texto_x, $posicion_texto_y, $blanco, $fuente, $texto);

header('Content-type: image/jpeg');
imagejpeg($img);

imagedestroy($img);
martes, 18 de diciembre de 2012

Conectar a un FTP con PHP para cargar, descargar y eliminar archivos

Contactarse a un servidor FTP y realizar todo tipo de acciones sobre los archivos alojados remotamente es posible gracias a las funciones específicas del leguaje PHP para trabajar con este protocolo. A excepción del comando mget (varios get) prácticamente todo lo que se puede hacer desde una línea de comandos FTP se puede llevar a cabo de una forma muy sencilla, subir y bajar archivos, eliminarlos, listar directorios, etc.

Vamos a ver un pequeño ejemplo en el que realizaremos algunas de las operaciones típicas. Para ello primero establecemos una conexión con el servidor FTP remoto, a continuación iniciamos sesión indicando nuestras credenciales de acceso para poder, primero descargar un archivo remoto, después subir un archivo al servidor, eliminarlo y finalmente listar los archivos ubicados en el directorio raíz del FTP.

$host = 'ftp.servidor-remoto.com';
$user = 'mi_usuario';
$pass = 'mi_contrasena';
$remote_file = 'copia_remota.txt';
$local_file = $_SERVER['DOCUMENT_ROOT'] . '/sitio/copia_local.txt';

//conectarse al host
$conn = @ftp_connect($host);

//Comprobar que la conexión ha tenido éxito
if (!$conn) {
echo 'Error al tratar de conectar con ' . $host . "\n";
exit();
}
echo 'Conectado con ' . $host . "\n";

//Iniciamos sesión
$login = @ftp_login($conn, $user, $pass);
if (!$login) {
echo 'Error al intentar acceder con el usuario ' . $user;
ftp_quit($conn);
exit();
}
echo 'Conectado con el usuario ' . $user . "\n";

//obtenemos el archivo del servidor
if (ftp_get($conn, $local_file, $remote_file, FTP_BINARY)) {
echo 'El archivo ' . $local_file . ' se ha guardado.' . "\n";
} else {
echo 'El archivo ' . $local_file . ' NO se ha guardado.' . "\n";
}

//subimos un archivo al servidor remoto
$remote_file = 'copia_remota.txt';
$local_file = $_SERVER['DOCUMENT_ROOT'] . '/sitio/copia_local.txt';;

if (ftp_put($conn, $remote_file, $local_file, FTP_BINARY)) {
echo 'El archivo ' . $local_file . ' se ha cargado en el servidor remoto.' . "\n";
} else {
echo 'El archivo ' . $local_file . ' NO se ha cargado en el servidor remoto.' . "\n";
}

//borramos el archivo del servidor
if (ftp_delete($conn, $remote_file)) {
echo 'El archivo ' . $remote_file . ' ha sido borrado del servidor.' . "\n";
}

//obtenemos una lista con los archivos del servidor
$files = ftp_nlist($conn, '.');
foreach ($files as $file) {
echo $file . "\n";
}

//Cerramos la conexion
ftp_close($conn);
viernes, 14 de diciembre de 2012

Subir archivos al servidor con PHP

El upload o subida de archivos al servidor mediante PHP es una tarea muy sencilla. Únicamente necesitamos un formulario HTML y manejar la matriz superglobal $_FILES. El formulario, que debe ser enviado utilizando el método POST, necesitará una entrada de carga de archivos de type file (type="file") con el que seleccionaremos el archivo a subir y un atributo para el tag form que indique al servidor que se va a adjuntar un archivo junto con el resto de información (enctype="multipart/form-data").

<form name="frm_upload" action="upload.php"
method="post" enctype="multipart/form-data">
<input type="file" name="archivo" />
</form>

Para procesar el archivo en el lado del servidor utilizaremos los siguientes elementos de la matriz $_FILES. Esta matriz toma el valor del atributo name del campo de tipo file como índice de su primera dimensión y almacena toda la información proporcionada por el archivo.

$_FILES['archivo']['tmp_name'] es la ruta temporal donde se ha guardado el archivo.
$_FILES['archivo']['name'] el nombre real del archivo en origen.
$_FILES['archivo']['size'] el tamaño del archivo en bytes.
$_FILES['archivo']['type'] tipo MIME del archivo subido al servidor.
$_FILES['archivo']['error'] código de error.

En el siguiente ejemplo cargamos un archivo en el servidor y si la operación tiene éxito informamos algunos detalles sobre el archivo subido.

//ruta donde colocaremos el archivo
$archivo = $_SERVER['DOCUMENT_ROOT'] . '/libro/18/uploads/' .
$_FILES['userfile']['name'];
//archivo temporal cargado en el servidor
$archivo_tmp = $_FILES['userfile']['tmp_name'];
$archivo_size = $_FILES['userfile']['size'];
$archivo_type = $_FILES['userfile']['type'];

if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
 if (!move_uploaded_file($archivo_tmp, $archivo)) {
  echo 'El archivo no ha podido ser ubicado en el directorio de destino.';
 } else {
  echo 'Archivo guardado correctamente.<br />';
  echo 'Ruta completa: ' . $archivo . '<br />';
  echo 'Tamaño archivo: ' . round($archivo_size / 1024, 2) . 'KB. <br />';
  echo 'Tipo: ' . $archivo_type . '<br />';
 }
}
martes, 7 de diciembre de 2010

Funciones útiles para el manejo de archivos con PHP

Estas son sólo algunas de las funciones para el manejo de archivos nativas en PHP.

file_exists() Comprueba la existencia de un archivo.

$path = $_SERVER['DOCUMENT_ROOT'] . '/directorio/archivo.txt';
if (file_exists($path) {
  //si el archivo existe lo abrimos y lo leemos
  $fp = fopen($path, 'rb');
  while (!feof($fp)) {
    $linea = fgets($fp);
    echo $linea . '<br />'
  }
}

filesize() determina el tamaño en bytes de un archivo.

filesize($_SERVER['DOCUMENT_ROOT'] . '/directorio/archivo.txt');

En PHP no existe una función "delete" para la eliminación física de archivos en el servidor. Para realizar esa tarea el lenguaje pone a nuestra disposición unlink()

unlink($_SERVER['DOCUMENT_ROOT'] . '/directorio/archivo.txt');
domingo, 5 de septiembre de 2010

Gestión de parámetros en funciones con PHP

La mejor forma de separar y organizar nuestro código es mediante el uso de funciones. PHP permite la definición de funciones con o sin parámetros, estos pueden ser opcionales o como veremos a continuación pasarlos a la función sin previamente haber sido definidos.

//definimos una funcion
//en principio no espera parametros
function no_params() {
  echo "Número de parámetros pasados a la función: ";
  echo func_num_args();
  echo "<br />";
  //obtenemos un array con todos
  //los parámtros pasados
  $args = func_get_args();
  foreach ($args as $arg) {
    echo $arg."<br />";
  }
}
//pero al llamarla le pasamos una
//lista de parámetros
no_params("param1", "param2", 12);
//con lo que obtenemos en pantalla
param1
param2
12

Expresiones regulares con PHP

Recordamos algunas reglas básicas para el uso y manejo de expresiones regulares en PHP.

Carácter Significado
\ Carácter de escape
^ Coincidencia al principio
$ Coincidencia al final
. Coincidencia con cualquier carácter excepto nueva línea \n
| Opción alternativa OR
( Inicio subpatrón
) Final subpatrón
* Se repite 0 o más veces
+ Se repite 1 o más veces
{ Inicio cuantificador min/max
} Final cuantificador min/max
? Subpatrón opcional
Carácteres especiales utilizados detro de corchetes
\ Carácter de escape
^ No, utilizado en una posición inicial
- Indica rangos de carácter

Veamos algunos ejemplos prácticos del uso de esta sintaxis con la ayuda de algunas funciones de PHP para buscar o reemplazar cadenas.

Podemos comprobar la existencia de subcadenas que coincidan con el patrón de la expresión regular con las funciones ereg() y eregi(). La única diferencia entre ellas es que eregi() es "case insensitive", es decir no diferencia entre mayúsculas y minúsculas, mientras que ereg() sí.

$cadena = "http://www.google.com";
ereg('^(http|https):\/\/', $cadena);
//devuelve true ya que la cadena
//empieza por http://

ereg_replace('^(http|https):\/\/', 'https://', $cadena);
//sustituimos http:// por https://

Otro función útil para el manejo de expresiones regulares con PHP es split. Con su ayuda podemos dividir cadenas y obtener un array con las subcadenas resultantes.

$cadena = "http://www.google.com";
$arr = split('\/\/|\.', $cadena);
while (list($k, $v) = each($arr)) {
 echo $v .'<br />'; 
}
//retorna
http:
www
google
com

Para realizar una comparación global de una expresión regular utilizamos la función preg_match_all() que buscará todas las coincidencias de la expresión regular dada y las introduce en un array en el orden que especifiquemos opcionalmente.

$cadena = "En el año 1942 Cristobal Colon descubrió américa. ";
$cadena .= "Murió en el 1506.";
preg_match_all("/[0-9]{4}/", $cadena, $coincidencias);
foreach ($coincidencias as $a) {
  foreach ($a as $v) {
    echo $v . '<br />'; 
  }
}
//imprime
1942
1506
sábado, 4 de septiembre de 2010

Sustitución de subcadenas con PHP

Más recursos para el manejo de strings str_replace() y substr_replace(). Sirven básicamente para buscar y reemplazar cadenas.

//podemos utilizar una variable o un array
//para indicar los terminos buscados
$arr_busca = array("hola", "clavel", "corazón");
$arr_reemplaza = array("adiós", "flor", "amor");
str_replace($arr_busca, $arr_reemplaza, "hola clavel, adiós corazón");
//resulta
adiós flor, adiós amor

Del mismo modo la función substr_replace permite buscar y reemplazar una subcadena de una cadena en función de su posición. Espera los parámetros: cadena, sustitución, inicio y longitud. Si el valor del parámetro inicio es positivo o 0 el desplazamiento se calcula desde el principio, si es negativo se establece con respecto al final de la cadena. El valor de longitud representa el número de caracteres que será sustituido, si es 0 la cadena de sustitución se inserta sin sobreescribir la cadena existente, si este es negativo representa el punto donde se dentendrá la sustitución.

$var = substr_replace($str, 'hola', 2, 0); 

Funciones prácticas para manipular cadenas con PHP

La manipulación de cadenas de texto es una de las tareas más comunes a la hora de trabajar con PHP. Este lenguaje incorpora de forma nativa un buen número de funciones que nos facilitan enormemente el manejo de strings. Vamos a repasar algunas de estas las funciones para manipular cadenas más comunes.

Función Descripción
strtoupper() Convierte la cadena pasada como parámetro en mayúsculas.
strtolower() Convierte la cadena en minúsculas.
ucfirst() Pone en mayúsculas el primer carácter de la cadena.
ucwords() Pone en mayúsculas la primera letra de cada palabra.
addslashes() Escapa carácteres especiales agregando la barra invertida correspondiente.
stripslashes() Elimina las barras de escape.

Ejemplos de uso de otras funciones.

//substr() retorna una subcadena a partir
//de los puntos indicados como parámetro incial y final
$var = substr("hola que tal", 1);
//devuelve
ola que tal

//si el valor inicio es negativo
//devuelve la parte final de la cadena
//con los caracteres indicados
substr("hola que tal", -3);
//devueve
tal

//el parámetro longitud sirve para
//indicar el número de carácteres a devolver
//si es positivo o la posición final de la
//secuencia de retorno si es negativo
substr("hola que tal", 0, 4);
//devuelve
hola
substr("hola que tal", 0, -4);
//devuelve
hola que

Para buscar subcadenas dentro de otras cadenas utilizamos strstr(), que espera que le pasemos 2 parámetros, primero el texto donde buscar y segundo el texto buscado. Devuelve el texto pasado como parámetro número 1 desde la posición donde se haya encontrado la cadena buscada o false en caso de no encontrarla.

$cadena = "En un lugar de la mancha";
echo strstr($cadena, "lugar");
//devuelve
lugar de la mancha

Para obtener la posición de una subcadena utilizaremos strpos() y strrpos() que funcionan básicamente igual que strstr() con la diferencia de que en lugar de devolver una subcadena devuelve su posición numérica.

$cadena = "En un lugar de la mancha";
echo strpos($cadena, "un");
//imprime 3 ya que 3 es la
//posición que ocupa "un" en la
//cadena principal

//podemos emplear un tercer parámetro
//que sirve para indicar la posición
//a partir de la cual comenzamos a buscar
echo strpos($cadena, "n", 3);
//devuelve 4 ya que no se ha tenido en cuenta
//la primera n de "En"

La función strrpos() realiza la misma tarea pero retorna la posición de la última coincidencia en lugar de la primera. Estas dos funciones devolverán false si no encuentran la subcadena buscada. Importante: utilizar comparaciones estrictas y el operador === para evitar falsos positivos.

jueves, 2 de septiembre de 2010

Contar elementos de un array con PHP

En muchas ocasiones se hace muy necesario obtener el número total de elementos incluidos dentro de una matriz. Existen en PHP varias funciones que nos devuelven esta información la más popular es count() que cuenta el número de items del array pasado como parámetro. Con la función sizeof obtendremos el mismo resultado.

Mención aparte merece array_count_values(), esta otra función lo que hace es contar el número de veces que se repite cada valor único dentro de la matriz que le pasemos como parámetro. Retorna un array asociativo similar a una tabla de frecuencia.

$arr = array("a", "b", "b", "c", "d", "d", "d");
$fr = array_count_values($arr);
//si recorremos este segundo array
foreach ($fr as $item => $veces) {
  echo $item.': '.$veces.'<br />';
}
//obtendremos
a: 1
b: 2
c: 1
d: 3
miércoles, 1 de septiembre de 2010

Formas de recorrer arrays con PHP

PHP dispone de múltiples estructuras para el manejo de bucles y por ende pone a nuestra disposición una serie de cómodas alternativas para recorrer y manejar arrays. Veamos unos cuantos ejemplos.

//matrizes indexadas numéricamente
$arr = range('a', 'e');
for ($i=0;$i<5;$i++) {
  echo $arr[$i];
}
//otra forma seria foreach
foreach ($arr as $letra) {
  echo $letra;
}

//matrices asociativas
$multiarr = array(
  'nombre'=>'David',
  'genero'=>'masculino',
  'edad'=>'36'
);

foreach ($multiarr as $clave=>$valor) {
  echo $clave.': '.$valor;
}
//otra forma de recorrer matrices asociativas
//es utilizando las instrucciones list() y each()
while ($el = each($multiarr)) {
  echo $el['key'].': '.$el['value'];
  //el indice key es equivalente a 0
  //y value a 1

}
//la función list() nos brinda
//la opción convertir los elementos key y value (0, 1)
//en 2 nuevas variables
while (list($clave, $valor) = each($multiarr)) {
  echo $clave.': '.$valor;
}

La función each() obliga a resetear con reset() el array una vez recorrido si lo queremos volver a utilizar.

//reubicamos el elemento actual
//al principio de la matriz
//antes de volverlo a recorrer
reset($multiarr);

Una array multidimensional es aquel que a su vez contiene en cada ubicación otras matrices. El concepto básico es similar al de una tabla con filas y columnas.

//matriz bidimensional
$arr = array(
  array('David','masculino',36),
  array('Felipe','masculino',26),
  array('Andrea','femenino',21)
);
//podemos recorrer este array utilizando
//un bucle for y un pequeño truco para
//acceder al indice mayor del array tanto
//de las filas como de las columnas
$filas = count($arr, 0);
//redondeo al alza con ceil()
$columnas = ceil(count($arr,1)/count($arr,0))-1);
echo 'Este arreglo tiene '.$filas.' filas y '.$columnas.' columnas';
for ($fil = 0; $fil < $filas; $fil++) {
  for ($col = 0; $col < $columnas; $col++) {
    echo $arr[$row][$col];
  }
}

Tal vez prefiramos almacenar los registros utilizando columnas con nombre, de nuevo echamos mano de las matrices asociativas y almacenamos el mismo conjunto de datos anterior pero con nombres en lugar de números por cada row.

$arr = array(
  array('Nombre'=>'David', 'Genero'=>'masculino', 'Edad'=>36),
  array('Nombre'=>'Felipe', 'Genero'=>'masculino', 'Edad'=>26),
  array('Nombre'=>'Andrea', 'Genero'=>'femenino', 'Edad'=>21)
);
for ($row = 0; $row < count($arr, 0); $row++) {
  foreach ($arr[$row] as $key => $value) {
    echo $key.': '.$value.'<br />';
  }
}
//o como hemos visto anteriomente
//podemos emplear list() y each() para
//asignar los distintos valores a las
//variables $key y $value para un más
//fácil manejo
for ($row = 0; $row < count($arr, 0); $row++) {
  while (list($key, $value) = each($arr[$row])) {
    echo $key.': '.$value.'<br />';
  }
}

Seguimos añadiendo dificultad a medida que vamos aumentando las dimensiones de nuestros arreglos o arrays. PHP no tiene límites en relación al número de dimensiones que podemos añadir, vamos a ver como recorreríamos un array de 3 dimensiones.

$arr = array(
  array(
    array('USER', 'David', 'masculino', 100),
    array('USER', 'Felipe', 'masculino', 26),
    array('USER', 'Andrea', 'femenino', 21)
  ),
  array(
    array('ADMIN', 'Sandra', 'femenino', 35),
    array('ADMIN', 'Pepito', 'masculino', 45),
    array('ADMIN', 'Maria', 'femenino', 19)
  ),
  array(
    array('CLIENT', 'Juan', 'masculino', 28),
    array('CLIENT', 'Olivia', 'femenino', 23),
    array('CLIENT', 'Santiago', 'masculino', 63),
    array('CLIENT', 'Vicen', 'femenino', 37)
  )
);
for ($capa = 0; $capa < count($arr, 0); $capa++) {
  echo 'Capa: ' . $capa . '<br />';
  for ($fil = 0; $fil < count($arr[$capa], 0); $fil++) {
    for ($col = 0; $col < count($arr[$capa][$fil], 0); $col++) {
      echo $arr[$capa][$fil][$col] . ' - ';
    }
    echo '<br />'; 
  } 
}

Y ya que andamos jugueteando con los arrays veamos ahora una forma de seleccionar una imagen de forma aleatoria de entre todas las que nos encontremos con la extensión jpg en un directorio dado.

$path = "img";
$d = opendir($path);
while ($img = readdir($d)) {
  if (pathinfo($path . $img, PATHINFO_EXTENSION) == 'jpg')
    $fotos[] = $img;
}
closedir($d);
shuffle($fotos);
echo "<img src=\"img/$fotos[0]\" />";

Podemos movernos o recorrer arrays con un mayor control utilizando algunas funciones específicas como each(), current(), reset(), end(), next(), pos(), prev().

Como ejemplo vamos a recorrer una matriz de forma inversa con la ayuda de end() y prev().

//situamos el puntero al final del array
$val = end($array);
//empleamos un bucle while y la función
//prev() para mover el puntero de forma inversa
while ($val) {
  echo $val;
  $val = prev($array);
}

Tenemos la posibilidad mediante array_walk() de aplicar una función personalizada a cada elemento de un array. Esto nos permite modificar o emplear cada item del arreglo de una misma forma. Esta función espera como parámetros, el array con el que trabajar, la función personalizada y opcionalmente un parámetro que pasaríamos a nuestra función.

//mostramos en pantalla el resultado
//de multiplicar cada elemento por el factor pasado
//como parámetro a nuestra función multiplicadora
$array = range(1, 10);
function multiplicador($value, $key, $factor) {
  echo $value * $factor;
}
array_walk($array, 'multiplicador', 3);
miércoles, 18 de agosto de 2010

Evitar inyección SQL con PHP

La inyección SQL es un tipo de vulnerabilidad muy común y relativamente sencilla de explotar (que me lo digan a mi). Se origina por una incorrecta gestión de las variables de entrada empleadas para construir nuestras consultas SQL.

PHP ofrece una función específica para prevenir este inconveniente mysql_real_escape_string() que básicamente se encarga de escapar todos los caracteres especiales de una cadena para su uso en una sentencia SQL.

$val = $_POST["txtId"];
$val = mysql_real_escape_string($val);
$sql = "SELECT * FROM tbl WHERE id = $val";
martes, 17 de agosto de 2010

Recuperar posición puntero después de utilizar un conjunto de resultados en PHP

Esta es una forma práctica de recuperar una posición concreta o resetear complentamente un conjunto de resultados después de que estos ya han sido utilizados.

Por ejemplo, si recorremos el resultado de cualquier consulta con mysql_fetch_assoc() o mysql_fetch_array() cuando queramos volver a acceder a ese conjunto de resultados ya no estará disponible puesto que el puntero interno se situa en la última posición.

Con mysql_data_seek() podemos mover el puntero a la fila específicada para el identificador de resultado. Debemos indicar dos parámetros, el primero corresponde al resultado que proviene de una llamada a mysql_query() y el segundo es la posición o número de la fila deseada del nuevo resultado, la siguiente llamada a mysql_fetch_row() devolverá esa posición.

$conn = mysql_connect("localhost", "user", "pass")
  or die(mysql_error());
mysql_select_db("basedatos", $conn);
$result = mysql_query("SELECT * FROM tabla", $conn)
  or die(mysql_error());
//recuperamos por primera vez el conjunto de resultados
while ($row = mysql_fetch_assoc($result)) {
  foreach ($row as $name => $value) {
    $salida .= $name . ": " . $value;
  }
}
//ahora el puntero interno se encuentra al final
//por lo que si queremos recuperar nuevamente los
//valores de $result debemos mover de nuevo
//a la posición 0
mysql_data_seek($result, 0);
//ahora podemos volver a recorrer el conjunto de resultados
while ($row = mysql_fetch_assoc($result)) {
  print_r(mysql_fetch_assoc($result)); 
}

Instalar Apache, PHP y MySql en Windows

Primero descargamos la última versión del servidor web Apache. Elegimos las opciones por defecto que nos ofrece el asistente de instalación. Una vez instalado accedemos a su configuración localizando el archivo httpd.conf. De momento lo único que comprobaremos es que el servidor Apache esté escuchando un puerto libre (Listen 8080). Lo lógico sería atender las solicitudes del puerto 80 que es el estándar, pero si ya está previamente instalado el servidor web Microsoft IIS (como es mi caso), Apache debe escuchar las peticiones que lleguen por el puerto 8080 para no entrar en conflicto, por lo que en este caso para comprobar que todo está OK escribimos en la barra de dirección del navegador http://localhost:8080

Descargamos la última versión de PHP, como lo vamos a usar con Apache, hacemos caso de las recomendaciones y elegimos la compilación VC6 x86 Thread Safe: "If you are using PHP with Apache 1 or Apache2 from apache.org you need to use the VC6 versions of PHP".

Copiamos el contenido del zip en C:\php

Ahora vamos a indicarle al servidor web Apache que debe utilizar PHP, para ello regresamos al archivo httpd.conf y localizamos la sección "Dynamic Shared Object (DSO) Support" y añadimos la siguiente línea:

LoadModule php5_module "c:/php/php5apache2.dll"

Importante: Si la versión de Apache es 2.2.x o superior la librería que hay que referenciar es php5apache2_2.dll

Apache 2.2.x Support: Users of Apache 2.2.x may use the documentation below except the appropriate DLL file is named php5apache2_2.dll and it only exists as of PHP 5.2.0.

Justo debajo de esta línea añadimos:

AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
PHPIniDir "C:/php"

Localizamos la sección DirectoryIndex y añadimos index.php como página de inicio:

<IfModule dir_module>
    DirectoryIndex index.html index.php
</IfModule>

Reiniciamos el servidor y ya debería funcionar PHP correctamente. Ahora solo queda adaptar el archivo php.ini a nuestras necesidades, habilitando los módulos o extensiones que vayamos a necesitar, no sin antes indicar la ruta donde se encuentran así:

extension_dir = "C:/php/ext/"

Por último, instalamos MySql siguiendo el asistente. La última vez que lo instalé me encontré con que no podía conectar vía mysql_connect() utilizando "localhost" como nombre del servidor ya que lanzaba el siguiente error:

Se produjo un error durante el intento de conexión ya que la parte conectada no respondió adecuadamente tras un periodo de tiempo, o bien se produjo un error en la conexión establecida ya que el host conectado no ha podido responder.

Este inconveniente se debe a la incapacidad del sistema operativo de resolver "localhost" hacia 127.0.0.1 Esto sucede tanto en Windows Vista como en Windows 7 ya que por defecto el archivo Hosts ubicado en C:/Windows/System32/drivers/etc trae la siguiente línea comentada:

#127.0.0.1     localhost

Solo hay que quitar la almohadilla y a funcionar.

lunes, 16 de agosto de 2010

MySql, PHP y la codificación utf8

Para evitar problemas con acentos, eñes, etc. y de paso maximizar la compatibilidad de nuestras páginas y bases de datos MySql con cualquier idioma y distintos conjuntos de caracteres, lo mejor es utilizar o establecer por defecto el tipo de codificación UTF-8.

La mejor opción es configurar el servidor MySql para que trabaje con codificación UTF-8 por defecto añadiendo estas líneas en el archivo my.ini localizar [mysqld].

default-character-set = utf8
character-set-server = utf8
collation-server = utf8_general_ci
init_connect = 'SET collation_connection = utf8_general_ci'
init_connect = 'SET NAMES utf8'

Si te interesa profundizar en el tema de los "encodings" y mysql no te pierdas este artículo del Blog personal de Jynus.

El servidor Apache también dispone de una directiva llamada AddDefaultCharset que debemos establecer como utf-8 para que no aparezcan caracteres extraños en lugar de acentos, eñes, etc.

AddDefaultCharset utf-8

En el php.ini la directiva default_charset también tiene algo que ver en todo este galimatias de tipos de codificación y caracteres.

default_charset = "iso-8859-1"

Mediante PHP también es posible configurar el charset en el momento de usar cualquier tabla, para ello debemos especificar el siguiente código después de realizar la conexión y la selección de la BD (mysql_connect – mysql_select_db) y antes de ejecutar cualquier consulta.

mysql_query ("SET NAMES 'utf8'");

En PHP 5.2 o superior podemos también usar:

mysql_set_charset("utf8", $conn);

Una función muy práctica que sirve para ver el charset que está devolviendo MySql.

mysql_client_encoding($conn);
sábado, 14 de agosto de 2010

Leer archivo XML con PHP utilizando simpleXML

Uno de los parsers XML más sencillos de utilizar que nos ofrece PHP es simpleXML. Viene por defecto en la versión 5 y posteriores de PHP. SimplePHP añade una serie de métodos para acceder de forma bastente sencilla a nuestros archivos XML.

//dado el siguiente archivo XML
<?xml version="1.0" encoding="utf-8"?>
<items>
  <item id="1">
    <nombre>Producto Uno</nombre>
    <precio>250</precio>
    <cantidad>2</cantidad>
  </item>
  <item id="2">
    <nombre>Producto Dos</nombre>
    <precio>120</precio>
    <cantidad>1</cantidad>
  </item>
  <item id="3">
    <nombre>Producto Tres</nombre>
    <precio>20</precio>
    <cantidad>5</cantidad>
  </item>
</items>

//cargamos el archivo XML
$xml = simplexml_load_file("items.xml");
//mostramos todo el contenido del archivo
$str = $xml->asXML();
//extraemos directamente un elemento
$producto = $xml->item[0]->nombre;
//obtenemos un array con todos los nodos
//que dependen del principal
$arr = $xml->children();
//recorremos la matriz de items buscando
//a la vez los descendientes del primer item
foreach ($arr->children() as $etiqueta => $valor) {
  echo $etiqueta . ": " . $valor;
}
//acceder a los atributos
//mostramos el atributo id del segundo item
echo $xml->item[1]["id"];
//mostramos solo los elementos con el atributo id par
foreach ($arr as $item) {
  if ($item["id"] % 2 == 0) echo $item->nombre;
}

Redirección 301 con PHP

Lo dicho cuando hablamos de la redirección 301 con ASP clásico es aplicable en este caso. La forma de hacer una redirección en PHP es igual de sencilla.

Header( "HTTP/1.1 301 Moved Permanently" );
Header( "Location: http://www.dominio.com" );

Header se utiliza para enviar una cabecera HTTP al navegador o cliente y debe ser llamada antes de que sea enviado cualquier otro tipo de salida, atención a los espacios o líneas en blanco que puedan colarse.

miércoles, 11 de agosto de 2010

Mostrar archivos dentro de un directorio con PHP

Resulta sorprendente la facilidad de uso de este lenguaje de programación, algo que vuelve a quedar patente en el siguiente ejemplo en el que con muy pocas líneas de código recorremos una carpeta o directorio y extraemos los nombres de todos los archivos con los que nos encontramos.

$d = opendir("./directorio");
while (($archivo = readdir($d)) !== false) {
  //readdir devolvera FALSE cuando
  //ya no encuentre ningun archivo
  $archivos[] = archivo;  
}
closedir($d);
//ahora tenemos un array con el nombre de
//cada uno de los archivos del directorio indicado

//si queremos limpiar el resultado eliminando "." y ".."
if ($archivo != "." && $archivo != "..") {
  $archivos[] = archivo;
}

Obtener rutas o paths con PHP

Obtenemos las distintas partes de una ruta con php, mediante el uso de pathinfo() accedemos a la información relativa a una ruta de archivo. Podemos indicar qué elementos son devueltos con el parámetro opcional options las distintas opciones son:

PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION y PATHINFO_FILENAME.

Si no indicamos ninguna de estas opciones pathinfo() devolverá una matriz con todos los elementos.

//realpath() devuelve el nombre de la ruta absoluta canonizada
$realPath = realpath("archivo.txt");
$pathParts = pathinfo($realPath);
//accedemos a las distintas partes de la ruta
$nombreDirectorio = $pathParts["dirname"];
$nombreArchivo = $pathParts["basename"];
$extension = $pathParts["extension"];

Pero si lo que buscamos es acceder a la base del arbol de documentos del servidor, podemos hacerlo de la manera tradicional.

$_SERVER['DOCUMENT_ROOT'];

Leer y escribir un archivo de texto línea a línea con PHP

Un ejemplo de como leer un archivo de texto txt línea por línea con php.

//Abrimos el txt generando un puntero hacia el archivo físico
$fp = fopen("archivo.txt");
//recorremos las diferentes lineas de texto
while (!feof) {
  $line = fgets($fp);
  echo $line . "<br />";
}
fclose($fp);
//importante cerrar el archivo al finalizar

También tenemos a nuestra disposición algunos métodos más para realizar este misma tarea, aunque con cierta funcionalidad extra como son fgetss() y fgetcsv().

//fgetss() elimina todos los tags HTML y PHP que encuentre. 
//Si queremos conservar alguno debemos indicarlo en el
//tercer parámetro, como en el siguiente ejemplo
@$fp = fopen($_SERVER['DOCUMENT_ROOT'].'/ruta/archivo.txt', 'rb');
if ($fp) {
 while (!feof($fp)) {
  echo fgetss($fp, 2096, '<strong><br>').'<br />'; 
 }
 fclose($fp);
} else {
 echo 'Error'; 
}

//fgetcsv() se utiliza para dividir las líneas
//según el caracter de delimitación pasado a la función
//imaginemos un archivo con el siguiente texto:
1,nombre cliente 1,codigo cliente 1,estado cliente 1
2,nombre cliente 2,codigo cliente 2,estado cliente 2
//podemos obtener esta información CSV de la siguiente forma:
$l = 1;
if ($fp = fopen($_SERVER['DOCUMENT_ROOT'].'/ruta/archivo.txt', 'rb')) {
 while ($d = fgetcsv($fp, 2096, ",")) {
  $n = count($d); 
  echo "$n campos en la fila $l<br />";
  $l++;
  for ($i = 0; $i < $n; $i++) {
   echo $d[$i].'<br />'; 
  }
  echo '<br /><br />';
 }
 fclose($fp);

} else {
 echo 'Error'; 
}

Para escribir en un archivo de texto prestamos atención a los modificadores de acceso a ficheros.

"r" => Sólo lectura
"w" => Escritura
"a" => Adición
"r+" "w+" => Lectura y escritura
"b" => Binario (se usa en combinación con alguno de los anteriores, se recomienda para maximizar la portabilidad entre sistemas Linux y Windows.

//Escribir en un archivo una nueva línea
$fp = fopen("archivo.txt", "a");
fputs($fp, "\nTexto a escribir");
fclose($fp);

En realidad fputs() es un alias de fwrite(). Otra opción para leer un archivo con php, es mediante el comando file() con el que no se requiere ningún tipo de puntero hacia el fichero, simplemente abre un archivo y devuelve una matriz con cada línea ocupando una posición. El problema con esta opción llega a la hora de manejar archivos muy grandes ya que pueden generar problemas de memoria. En estos casos siempre es mejor hacerlo accediendo al contenido del fichero línea a línea con fgets() como hemos visto antes.

$salida = "";
$archivo = file("archivo.txt");
foreach ($archivo as $linea) {
  $lineaActual = $linea;
  $salida .= rtrim($lineaActual) . "<br />\n";
}
echo $salida;
martes, 10 de agosto de 2010

Recoger y filtrar campos de formulario con PHP

Bueno, decir que no me gusta demasiado la plataforma de blogs de google, una administración muy pobre, muchas cosas no funcionan como deberian o al menos como a mi me gustaria, realizar cualquier ajuste o corregir alguna cosa se convierte en un calvario y muy poca, por no decir nula documentación oficial en español. Pero ya que lo que quiero es simplemente un lugar donde tener disponible algunos recursos que pueden venir bien en cualquier circunstancia y lugar, voy a utilizarlo como bloc de notas online a ver que tal.

Por cierto, aprovecho para dar las gracias a vagabundia un blog muy recomendable, que me ha sido de gran ayuda para darle un poquito de forma a esto.

Ahora a lo que iba, ejemplo para filtrar entradas desde un formulario en php. Con filter_input tomamos una variable externa concreta por nombre y opcionalmente se puede filtrar.

filter_has_var comprueba que una variable de un tipo concreto existe.

Estas dos funciones admiten INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER o INPUT_ENV

//recoge un campo de formulario vía POST
filter_input(INPUT_POST, "txtform");
//comprueba si viene el campo de formulario txtform
//aunque este vacio devuelve TRUE
filter_has_var(INPUT_POST, "txtform");