Mostrando entradas con la etiqueta php. Mostrar todas las entradas
Mostrando entradas con la etiqueta php. Mostrar todas las entradas

jueves, 21 de mayo de 2015

Creando un catpcha usando PHP GD

Actualmente hay un monton de librerias de captchas en la web, como anteriormente mostre una de google captcha: http://arthusu.blogspot.mx/2014/09/resumen-recaptcha.html

Un desarrollador debe conocer como un captcha es generado. En este tutorial iremos paso a paso como crear un captcha usando PHP GD. El captcha es una cadena generada aleatoria generada automaticamente por numeros/letras, la cadena generada es guardada en algo (como sesiones o base de datos), cuando el usuario envia el formulario, este verifica si el texto introducido por el usuario es igual a la cadena generada y almacenada en la sesion por ejemplo, si coinciden asume que el que ingreso la cadena es un humano y no un bot y el proceso seguiria. En estos dias hay capchas de matematicas tales como 5x_ = 20 y si llenaras el espacio vacio con 4 que seria 5x4 = 20 el formulario es validado. En este tutorial solo nos concentraremos en una imagen de captcha. Para generar un captcha lo que necesitamos nosotros es una cadena aleatoria, para ello utilizaremos la libreria PHP GD, en la mayoria de los casos esta libreria viene instalada por defecto en los servidores. Asi que no discutiremos como instalarla. PHP GD tienen varias funciones para generar imagenes en varios formatos, nosotros comenzaremos con imagecreatetruecolor:

$im = imagecreatetruecolor('150','50');

Lo anterior crea una imagen de 150px de ancho y 50px de alto. Note que $im contiene el recurso de la imagen y no la imagen actual. Nosotros agregaremos componentes a la imagen tal como fondos, cadenas de texto. En este caso requerimos tres colores: primero para el fondo, segundo para la cadena y tercero para hacer unos pixeles de ruido, para que el captcha sea dificultoso para que los bots lo lean. Antes de aplicar estos colores a nuestro recurso de imagen $im primero tenemos que crear los tres colores:

$bg = imagecolorallocate($im, 230, 80, 0); // fondo naranja
$fg = imagecolorallocate($im, 255, 255, 255); // texto blanco
$ns = imagecolorallocate($im, 200, 200, 200); // ruido color gris

Los ultimos tres parametros para imagecolorallocate son el rgb para color. Y el primer parametro es el recurso de la imagen. Entonces ahora tenemos los colores listos, ahora necesitamos llenar la imagen con estos colores, primero agregemos el color de fondo:

imagefill($im, 0, 0, $bg); // el segundo y tercer parametro son las coordenadas x e y para comenzar el llenado de color

Ahora agregamos algunos caracteres a la imagen. Por ahora nosotros agregaremos la palabra 'captcha' pero esta debe ser generada automaticamente en el codigo final.

imagestring($im, 5, 10, 8, 'captcha', $fg);

imagestring dibuja la cadena 'captcha' como quinto parametro. El segundo parametro 5 es el tamaño de la fuente. 10 y 8 son de la esquina arriba a la izquierda las coordenadas x e y para comenzar la cadena desde ese punto. El primer parametro es el recurso de imagen y el ultimo es el color de la cadena. Nosotros agregamos un color de fondo, y una cadena de texto. Esta oficialmente hecho. Pero algunos bots son capaces de leer imagenes. Entonces para defendernos nosotros agregaremos un poco de ruido a la imagen para que solo la puedan leer los humanos y los bots no. 

imagesetpixel($im, 2, 4, $ns);

El codigo de arriba agrega un pixel en la coordenada (2,4) medido desde la esquina arriba izquierda. Obviamente necesitas varios de estos para que la imagen sea mas dificultosa de leer. Ahora es cuando generamos nuestra imagen utilizando imagepng creamos una imagen fuera del recurso $im. Y podemos crear nuestra imagen. 

imagepng($im);

Una buena practica que debemos de tener es destruir la imagen creada, despues de que es mostrada por el navegador ya no la requerimos mas.

imagedestroy($im);

Para que la imagen sea mostrada por el navegador necesitamos enviar algunas cabeceras del tipo de contenido de imagen, en este caso png. El codigo de abajo es llamado antes de que la imagen sea enviada al navegador. Esto es antes de imagepng($im).

header('Cache-Control: no-cache, must-revalidate');
header('Content-type: image/png');

El codigo de abajo es el codigo total. Nota que agregamos todas las funciones y sus parametros discutidos anteriormente. El proposito es agregar nuestro codigo dinamico. Tambien el fondo de ruido con la funcion imagesetpixel es agregado dentro de un loop para ser llamado varias veces. y por ultimo los caracteres del captcha son agregados aleatoriamente. El captcha aleatorio es almacenado en $_SESSION['captcha_code'].

 


 <?php
 
//ancho y alto de la imagen a crear
$width = 90;
$height = 30;
 
//Cantidad de fondo para agregar el ruido a la imagen
$noise_level = 15;
 
//generamos codigo aleatorio en caso de que queramos usar numeros:
//$code=rand(1000,9999);
 
// generamos codigo aleatorio en caso de que queramos usar letras y numeros:
$chars = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
// el tamano del captcha en caracteres ?lenght=5...
$length = (isset($_GET['lenght']) && is_numeric($_GET['lenght'])) ? (int)$_GET['lenght'] : 8;

// Es agregado el captcha aleatorio en la variable $code
$code = "";
for ($i = 1; $i <= $length; $i++)
{
 $code .= $chars[mt_rand(0, strlen($chars)-1)];
}


// guardamos la sesion para la validacion del formulario
session_start();
$_SESSION["captcha_code"]=$code;
 
//creamos el recurso de imagen
$im = imagecreatetruecolor($width, $height);
$bg = imagecolorallocate($im, 230, 80, 0); //color de fondo
$fg = imagecolorallocate($im, 255, 255, 255);//color de texto
$ns = imagecolorallocate($im, 200, 200, 200);//color de ruido
 
//llenamos la imagen del color fondo
imagefill($im, 0, 0, $bg);
 
//Agregamos la cadena aleatoria a la imagen
imagestring($im, 5, 10, 8,  $code, $fg);
 
//Agregamos ruido a la imagen
for ($i = 0; $i < $noise_level; $i++) {
    for($j = 0; $j < $noise_level; $j++) {
        imagesetpixel(
            $im,
            rand(0, $width), 
            rand(0, $height),// nos aseguramos que los pixeles no se salgan de la imagen agregando sus respectivos ancho y alto
            $ns
        );
    }
}
 
//le decimos al navegador el tipo de aimgen
header("Cache-Control: no-cache, must-revalidate");
header('Content-type: image/png');
 
//generamos la imagen
imagepng($im);
 
//destruimos la imagen
imagedestroy($im);
?>


Guardamos el codigo en un archivo php como captcha.php, ahora podemos usar el archivo como recurso de imagen, us uso es simple:

<form method="post" action="">
    <img src="captcha.php">
    <input type="text" name="captcha_code">
    <input type="submit" name="enviar">
</form>



En caso de que queramos agregar menos caracteres (aunque en realidad esta funcion es irrelevante y podria causar problemas futuros), es una buena demostracion:

<form method="post" action="">
    <img src="captcha.php?lenght=4">
    <input type="text" name="captcha_code">
    <input type="submit" name="enviar">
</form>


Ahora para validar el formulario con el captcha por el lado del servidor es como lo siguiente:

    session_start();
    if (isset($_POST['enviar'])) {
        if($_POST["captcha_code"] == $_SESSION["captcha_code"] ){
            //El captcha es correcto, entonces el formulario es procesado.
            echo "Correcto!";
        }
        else{
            //Los caracteres del captcha no coinciden.
            echo "Codigo captcha incorrecto.";
        }
    }



El capcha tambien nos ayuda contra ataques de fuerza bruta como comentamos en el tutorial de seguridad de php numero 7.


Espero que este post les haya sido de utilidad.

Publicacion original: http://perials.com/tutorial-creating-image-captcha-php-using-gd-library/

miércoles, 6 de mayo de 2015

[PHP]Filtros con la libreria GD

Buenas en este caso utilizaremos la libreria PHP GD para aplicar algunos efectos comunes utilizando la funcion imagefilter():

bool imagefilter ( resource $image , int $filtertype [, int $arg1 [, int $arg2 [, int $arg3 [, int $arg4 ]]]] )

Como se describe la sintaxis arriba, necesitamos un recurso de imagen, una constante que aplicara el filtro (varios incluyen opciones y otros no).

Vamos a explicar algunas de las opciones que podremos usar.

IMG_FILTER_NEGATE - Esto lo que hace es negar los colores de la imagen (invertirlos).

IMG_FILTER_GRAYSCALE - Convierte la imagen a escala de grises.

IMG_FILTER_GAUSSIAN_BLUR - Pone la imagen borrosa utilizando el metodo Gaussiano.

IMG_FILTER_EMBOSS - Pone en relieve la imagen.

IMG_FILTER_EDGEDETECT - Detecta los bordes de la imagen para resaltarlos.

IMG_FILTER_BRIGHTNESS - Cambia el brillo de la imagen. Tiene un argumento el cual puede ir del valor -255 a 255.

IMG_FILTER_COLORIZE - Le da un color a toda la imagen, se usan tres parametros RGB (rojo, verde y azul), tambien puedes usar un cuarto parametro para valores alpha que va desde 0 a 127 lo cual le da transparencia a la imagen.

IMG_FILTER_CONTRAST - Cambia el contraste de la imagen.
Tiene un argumento el cual puede ir del valor -255 a 255.

IMG_FILTER_SMOOTH - Suaviza la imagen. Los valores recomendados son de -8 a 8 para que la diferencia se note pero no exageradamente.

Ahora veremos dos ejemplos en practica:

Codigo:

$image = imagecreatefrompng("ay2bdLJ.png");
imagefilter($image, IMG_FILTER_NEGATE); // negar colores

header("content-type: image/png");
imagepng($image);
imagedestroy($image);

Imagen: http://i.imgur.com/HOINYIr.png
Filtro Aplicado: IMG_FILTER_NEGATE
Resultado: 



Codigo:
$image = imagecreatefrompng("space.png");
imagefilter($image, IMG_FILTER_COLORIZE,255,0,0); // le da color a la imagen, red green blue
header("content-type: image/png");
imagepng($image);
imagedestroy($image);

Imagen: http://i.imgur.com/Nix7KLI.png
Filtro Aplicado: IMG_FILTER_COLORIZE
Resultado:


Y hasta aqui esta pequeña introduccion, es muy facil de usar, pero los efectos son bastante buenos, saludos!

lunes, 4 de mayo de 2015

[PHP] Creando una firma dinamica

Introduccion

Buenas he estado sin tiempo para postear pero en esta ocasion les mostraré como crear una firma dinamica de manera que obtengan algunos datos, muchos ya saben como realizarlo por que no tiene tanta dificultad mas que nada se trata de utilizar la libreria de PHP GD.

Un buen tutorial que recomiendo mucho sobre PHP GD es el siguiente: http://wiki.elhacker.net/programacion/php/libreria-gd el cual esta muy bien explicado.
Tratare de ser breve colocando solo los pasos.

Estructura a realizar

La estructura con la que trabajaremos sera la siguiente:


Explicando un poco que hace cada archivo.

.htaccess - Con este archivo interpretaremos imagenes png (con su extension .png) como archivos php y bloquearemos cualquier intento de acceso al archivo logs.txt

firma.php - Con este archivo generamos la imagen dinamica (pronto le cambiaremos la extension a .png)

KeepCalm-Medium.ttf - Es el tipo de letra que utilizaremos para la firma dinamica.

logs.txt - Aqui guardaremos los logs, en este caso IP, Sistema, Si usa proxy.

rVJgsdx.png - Es la imagen que utilizaremos para la firma dinamica. 

view_logs.php - Este es un archivo para ver los logs online. Con un simple formulario que tiene que ingresar una clave.

Nota importante: Nada de aqui es guardado en una base de datos. Y esto es facilmente explotable haciendo peticiones desde la misma IP un sin fin de veces cargaria todo el archivo logs.txt haciendolo demasiado pesado (Esa idea la hizo un amigo JhonJhon_123) entonces lo unico que podemos realizar en este caso es:

1.- Denegar las ips que realizen demasiadas peticiones
2.- No insertar IPS repetidas en el archivo logs.txt
3.- Cambiar el nombre de la carpeta para que no hagan mas peticiones.

Cualquiera de estos tres puntos no se ven en este tutorial.

Creando la firma

En este caso crearemos el archivo PHP para realizar la firma dinamica, no entrare en detalles de explicaciones ya que comente el codigo lo mas posible para que se entendiera, de todas maneras si no entienden algo, arriba deje una buena documentacion con la que pueden guiarse.

 <?php
 // no reportamos errores
 error_reporting(0);
 // el nombre de la imagen a poner como firma
 $im_name = "rVJgsdx.png";
 // los datos de la imagen
 $data_im = getimagesize($im_name);
 // el tipo de imagen
 header("Content-type: {$data_im['mime']}");
 // creamos la imagen en este caso png 
 $im = imagecreatefrompng($im_name);
 // creamos un color para usarlo en el texto
 $color = imagecolorallocate($im, 45, 196, 236);
 // obtenemos la IP
 $ip = $_SERVER['REMOTE_ADDR'];
 // obtenemos los datos del navegador
 $user_agent = $_SERVER['HTTP_USER_AGENT'];
 // vemos si existe algun proxy (no es 100% fiable), y lo agregamos a la variable ip
 $proxy_headers = array(
        'HTTP_VIA',
        'HTTP_X_FORWARDED_FOR',
        'HTTP_FORWARDED_FOR',
        'HTTP_X_FORWARDED',
        'HTTP_FORWARDED',
        'HTTP_CLIENT_IP',
        'HTTP_FORWARDED_FOR_IP',
        'VIA',
        'X_FORWARDED_FOR',
        'FORWARDED_FOR',
        'X_FORWARDED',
        'FORWARDED',
        'CLIENT_IP',
        'FORWARDED_FOR_IP',
        'HTTP_PROXY_CONNECTION'
    );
    foreach($proxy_headers as $x){
        if (isset($_SERVER[$x])) {
         $ip .= "/Estas usando proxy!";
         break;
        }
    }

    // reemplazamos los datos del navegador en caso de que sea firefox por firefox o chrome por chrome, la lista es corta se pueden agregar mas
 $navegador = preg_replace('/.*(firefox|chrome).*/i', '$1', $user_agent);
 // lo mismo que arriba en este caso con el sistema, igual podemos hacer la lista personalizable
 $sistema = preg_replace('/.*(windows|mac|linux).*/i', '$1', $user_agent);
 // guardamos los datos en una variable para usarla en el texto
 $string = " Tu IP: $ip \n Tu navegador: $navegador \n Tu sistema: $sistema \n Te estoy vigilando!\n";
 // asignamos una variable con la fuente para usarla en el texto
 $fuente = "KeepCalm-Medium.ttf";
 // en caso de que no se haya detectado nada mostramos el navegador, aunque nos trolleen xD :P
 if($navegador == ''){
  $navegador = $_SERVER['HTTP_USER_AGENT'];
 }
 // what? :3, Guardamos logs
 $manejador = fopen("logs.txt", 'a+');
 fwrite($manejador, "$string\n\n\n");
 fclose($manejador);
 // magia is here! Mostramos el texto en las coordenadas dadas
 imagettftext($im, 10, 0, 300, 10, $color, $fuente, $string);
 // png transparency, para la transparencia en la imagen sino se veria desfigurada
 imagealphablending($im, true);
 imagesavealpha($im, true);
 imagepng($im);
 // destroy image, liberamos la memoria
 imagedestroy($im);
?>



Asignar formato a la imagen y denegar acceso a los logs

En este apartado crearemos el archivo .htaccess el cual denegara acceso a los logs y interpretara nuestro archivo png como php.

AddType application/x-httpd-php .png
<FilesMatch "\.(txt)$">
  Order Deny,Allow
  Deny from all
</FilesMatch>

Creando archivo para ver los logs

Por ultimo creamos nuestro archivo view_logs.php con el cual veremos los logs. 

 <?php
 if (isset($_POST['pass']) && !empty($_POST['pass']) && $_POST['pass'] == 'tucontraseñae.e') {
  $gestor = fopen('logs.txt', 'r');
  $contenido = fread($gestor, filesize('logs.txt'));
  fclose($gestor);
  echo "<pre>" . $contenido . "</pre>";
 }
?>
<form method="post" action="">
 <p><input type="text" name="pass" /></p>
 <p><input type="submit" name="enviar" /></p>
</form>

En este caso solo hay que cambiar tucontraseñae.e por la contraseña que le quieras asignar a la entrada.

Finalizando

Le cambiamos la extension al archivo firma.php y le ponemos el nombre que queramos en mi caso firma.png
Lo abrimos en el navegador para ver los resultados.


En este caso mi ip es ::1 ya que es una ip local.

Les dejo por ultimo los archivos por si quieren probarlo, igual pueden realizar el suyo propio cambiando algunas funciones como dependiendo del tipo de imagen que sea JPEG, PNG, etc. el tipo de letra, sus datos, etc. De igual manera con esto podrian crearse hasta generadores de firmas, saludos!

Archivos: http://www.mediafire.com/download/wr4yeydjyoyc397/firma_dinamica.rar
 

miércoles, 8 de abril de 2015

PHP 5.6 y el operador Splat

Tenemos un par de nuevas caracteristicas que vienen a PHP 5.6 con nombres que suenan mucho menos interesantes de lo que realmente representan "funciones variadicas" suena positivamente academica, y "desempaquetado de argumento" no es exactamente atrayente. Sin embargo ambos utilizan un nuevo operador en PHP que parece una elipsis (tres puntos ...) y que se conoce como operador de splat o el operador de dispersion. 

Funciones variadicas

Esta caracteristica le permite capturar un numero variable de argumentos a una funcion, combinada con argumentos "normales" aprobadas en si lo desea. Es mas facil de ver con un ejemplo:

 <?php
 function concatenate($transform, ...$strings){
  $string = '';
  foreach($strings as $piece){
   $string .= $piece;
  }
  return ($transform($string));
 }

 echo concatenate("strtoupper","I'd ","Like ", 4+2 , " Apples");
?>

La lista de parametros en la declaracion de la funcion tiene el operador ..., que basicamente significa "... y todo lo demas debe ir en $strings" puede pasar 2 o mas argumentos en esta funcion y la segunda y siguientes se añadira en el array $strings, listo para ser utilizado.

Desempaquetar argumentos

Este tiene un nombre menos sexy que las funciones variadicas, y utiliza el mismo operador pero este es el que me hizo describo codigo PHP como "salvaje" - no es algo que sucede a menudo! Me gusta por que ofrece una forma diferente de utilizar las funciones que ya existen por lo que hace pertinente tan pronto como actualizar a 5.6. 
Las funciones variadicas le permite declarar un array como parametros de entrada, y desempaquetar argumentos le permite pasar un array a una funcion que espera parametros distintos en la forma tradicional; son absolutamente complementarias entre si. Para usar esta funcion, simplemente advertir a PHP que necesita para desempaquetar el array en las variables utilizando el operador ... Un ejemplo sencillo podria tener este aspecto:


 <?php
 $email[] = "Hi there";
 $email[] = "Thanks for registering, hope you like it";

 mail("someone@example.com", ...$email);
?>


Puede pasar todos los argumentos en forma de array (consejo pro: array asociativos no funcionan aqui), o simplemente el ultimo, PHP toma su matriz y pasa cada elemento como parametro siguiente a su vez. Creo que esto es bastante ordenado :).


Fuente: http://www.lornajane.net/posts/2014/php-5-6-and-the-splat-operator

domingo, 5 de abril de 2015

[PHP] Creando un convertidor a MP3 rapido y facil

Buenas tenia ya rato sin escribir algo, bueno espero ser rapido y breve, en esta entrada veremos sobre como crear un convertidor MP3 rapido y facil, en este caso estare utilizando windows, ustedes pueden bajarse el FFMPEG desde su pagina oficial para linux o macosx.

Bueno para ser mas breve posible lo que hare sera mostrar el script e ir explicando por pasos.

Esta es la estructura de nuestro proyectin:



 

 <?php
// sin limite de tiempo
set_time_limit(0);
// para que muestre errores
ini_set("display_errors",1);
error_reporting(E_ALL); 
// para que podamos subir archivos pesados 200MB
ini_set('upload_max_filesize', '200M');


// si se envio el formulario
if(isset($_POST["submit"])) {
 // el directorio a donde ira el video o archivo que conviertas en mp3
 $target_dir = "uploads/";
 // aqui se guarda el mp3
 $generador_archivo = "mp3/file_".md5(mt_rand()).".mp3";
 // el nombre del archivo a subir con su directorio a donde ira
 $target_file = $target_dir . basename($_FILES["file"]["name"]);

 // movemos el archivo
    if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) {
     // Aqui esta la magia! convertimos el archivo (Cuidado con la ejecucion de comandos XD)
     exec("ffmpeg -i \"$target_file\" $generador_archivo",$output,$return);
     // debug
     //print_r($output);
     // Si se ejecuto correctamente mostramos el enlace al archivo sino un error
     if(!$return){
         echo "<a href=\"mp3/". basename($generador_archivo). "\">Bajar Archivo</a>.";
        }else{
         echo "ERROR";
        }
    // si no se pudo mover el archivo ocurrio un error al subir
    } else {
        echo "Ocurrio un error al subir archivos";
        // debug
        //print_r($_FILES);
    }
}
?>
<!DOCTYPE html>
<html>
<body>

<form action="" method="post" enctype="multipart/form-data">
    Selecciona el archivo a convertir:
    <p><input type="file" name="file" id="file"></p>
    <p><input type="submit" value="Subir Archivo" name="submit"></p>
</form>

</body>
</html> 


Antes de comenzar a explicar el script, les dire que no es nada "seguro", ya que no le agregue seguridad para que se vea lo mas simple posible, pero si ustedes gustan pueden modificarlo. Y otra cosa es que para poder subir este script a un servidor tenemos que buscar que soporte FFMPEG o simplemente tener un servidor dedicado.
Aunque viene todo comentado, explicare...


1.- Le damos un set_time_limit(0) para que se ejecute el script hasta que termine. Mostramos errores con error_reporting y con ini_set establecemos la directiva de PHP.ini para mostrar errores. Establecemos upload_max_filesize en 200M para subir archivos pesados, muchas de las veces las directivas de PHP no te permiten solo con ini_set por lo que tendras que modificarlo desde el archivo de configuracion php.ini.

2.- Comprobamos si existe el formulario con isset($_POST['submit']), asignamos unas variables para la ruta, con md5(mt_rand()) genero un md5 aleatorio para que el archivo mp3 no se repita el nombre.

3.- movemos el archivo con move_uploaded_file a la ruta que asignamos.

4.- El comando mas importante es el comando de sistema exec, el cual realiza la conversion con el programa FFMPEG. La sintaxis es la siguiente:

ffmpeg.exe -i elarchivoaconvertir.mp4 elarchivodesalida.mp3

5.- Por ultimo verificamos que no haya retornado errores y mostramos el enlace en caso contrario mostramos un mensaje de error.
Con los print_r() podemos debuggear las matrices en caso de error.

Ya que nunca pongo imagenes pondre algunas, ya que dicen que "una imagen vale mas que mil palabras", yo les pondre 3 xD...




 

 Listo. Espero que esta entrada les haya sido de utilidad.

domingo, 15 de marzo de 2015

Comprimir directorios completos de tu sitio web

Buenas hoy estaba escuchando musica y luego un amigo (NoVaTo) me hablo por Skype diciendome que si tenia algun script o shell que comprimiera toda la pagina web para bajarsela, entonces como no tenia me puse a buscar como hacerlo uno a mi manera... hasta que al final di con bola... pues nada mas les dejo el script par aque lo usen cuando quieran:


 <?php
// Si son demasiados archivos colocamos el tiempo limite en 0 (sin limite)
set_time_limit(0);
 /*
  @autor : Arthusu
  @fecha : 15/03/2015
  @descripcion : Compresor de todos los archivos del directorio
  @archivo : compresor.php
 */

 // definimos las variables (las podemos modificar segun sea nuestro caso)
 $nombre_del_archivo_comprimido = "comprimido.zip"; // el nombre del archivo a generar
 $ruta_relativa = ""; // el directorio que nos encontremos. Ejemplo: images/algo/ para generar un link correcto

 if(phpversion() >= "5.2.0"){ // verificamos que contengan la version correcta para crear archivos zip
  $zip = new ZipArchive(); // Creamos un nuevo objeto
  if($zip->open($nombre_del_archivo_comprimido,ZIPARCHIVE::CREATE) === TRUE){ // creamos un archivo
   $iterator = new RecursiveDirectoryIterator(__DIR__); // recorremos el directorio
   $recursiveIterator = new RecursiveIteratorIterator($iterator); // recorremos los directorios dentro de otros directorios y asi sucesivamente

   foreach($recursiveIterator as $entry){ // recorremos los archivos
     if(is_file($entry->getRealPath())){ // verificamos que sea archivo
      // debug
      //echo $entry->getRealPath()."\n";
         $zip->addFile($entry->getRealPath()); // lo agregamos al zip
        }
   }
   // mostramos un enlace con los archivos
   echo $zip->numFiles .' archivos comprimidos: <a href="http://'.strip_tags($_SERVER["HTTP_HOST"]. "/" . $ruta_relativa . $nombre_del_archivo_comprimido).'">Descargar Archivo</a>';
  }else{
   // si no se crea el archivo mostramos el error
   echo "Ha ocurrido un error: ".$zip->getStatusString();
  }
  // cerramos el archivo zip
  $zip->close();
 }else{
  // si la version no es correcta mostramos un mensaje
  echo "Su version de PHP debe ser 5.2.0 o superior";
 }
?>

El uso es bastante facil.

1.- Subir el archivo a la carpeta que quieras comprimir 
2.- Ejecutar el archivo en la url: ejemplo.com/compresor.php
3.- Te generara un link donde descargar el archivo

Hay dos variables que puedes modificar dentro del archivo:

$ruta_relativa - Esta variable la modificas en caso de que te encuentres en una ruta relativa en alguna carpeta de la web, ejemplo: jquery/imagenes/, con eso nos generaria un link como el siguiente:  ejemplo.com/jquery/imagenes/comprimido.zip

$nombre_del_archivo_comprimido - Aqui puedes especificar el nombre del archivo resultante

Nota: Otra cosa a tomar en cuenta es que el script tarda dependiendo de que tantos archivos tenga que guardar o recorrer, puede tardar varios minutos dependiendo de que tantos archivos contenga tu sitio.

Y bueno eso es todo espero que la herramienta les sea de utilidad.

miércoles, 11 de febrero de 2015

PHP Interfaz de comandos

PHP es conocido y amado como una de las mejores tecnologias para la generacion de sitios web dinamicos. Pero a traves de la linea de comandos de PHP (CLI), tambien puede realizar shell scripting (programacion de linea de comandos) usando su lenguaje favorito PHP. PHP CLI permite ejecutar scripts PHP e incluso fragmentos de codigo PHP fuera del navegador web. En windows, la accion se lleva a cabo dentro de la ventana DOS (tambien conocida como consola o ventana de comandos). En UNIX y Mac OS X, va utilizar una terminal (o un programa similar).

Prueba de su instalacion 

Para comenzar, lo primero que debemos hacer es confirmar que nosotros tenemos PHP CLI disponible, entonces veremos la version.
Con suerte es cuestion de solo seguir unos pasos.

1.- Abra una interfaz de comandos
2.- ponga php -v y pulse la tecla enter o retorno



Si la version de PHP CLI se encuentra instalado en su PATH (Lista de ubicaciones donde el sistema operativo puede encontrar los archivos) con esto deberia ser mas que suficiente.

En el peor de los casos suponiendo que PHP CLI esta instalado, usted tendra que moverse a la ruta de PHP CLI o poner la ruta completa. Junto a la opcion -v, hay otros tres que podemos mostrarle por adelantado:


* -i revela informacion sobre la instalacion de PHP.
* -h accede al archivo de ayuda.
* -m indica los modulos compilados en su instalacion de PHP.

Uso de la CLI

El hecho de que usted pueda realizar script desde la linea de comandos con PHP no significa que siempre deba utilizarlo. En realidad lo que trata PHP es que utilices los conocimientos que ya tienes en PHP en lugar de utilizar algun otro lenguaje de CLI como PERL o shell en los cuales tengas que volver a iniciarte en la sintaxis. PHP CLI nos sirve mucho para realizar tareas basicas tales como:

* Probar fragmentos de codigo PHP rapidamente
* Realizar algun mantenimiento rutinario
* Crear utilidades para el sistema
* Hacer instaladores para sus aplicaciones de PHP

Ejecutando pequeños fragmentos de codigo

Uno de los primeros usos de PHP CLI es probar pequeños fragmentos de codigo rapidamente, sin pasar por el proceso de:

1.- Escribir un script formal de PHP
2.- Colocarlo en un directorio web
3.- Habilitar el servidor web, si no esta ON (activo)
4.- Ejecutar el script PHP en un navegador web

En vez de hacer todo eso, puede probar pequeños fragmentos de codigo con esta sintaxis:

php -r 'codigo_php_aqui'

Para un ejemplo:

php -r "echo 'Hola, mundo!';"

Un par de cosas a tener en cuenta es el uso de comillas dobles o comillas simples (esto dependiendo del sistema operativo donde estes trabajando) y siempre cerrar el codigo usando ; (punto y coma).

Tambien podemos conectar a un servidor remoto usando putty para conectar, solo es necesario ingresar nuestras credenciales.


Para continuar con el ejemplo, vamos a realizar un codigo que nos muestre la ultima modificacion de un archivo, en el cual podemos especificar la ruta completa o movernos al directorio donde se encuentra el archivo.

C:\Users\arthusu>php -r "$filename = 'log.txt'; $fmtime = filemtime($filename);
if(file_exists($filename)){ echo date('F d Y H:i:s',$fmtime); }"
May 02 2014 07:57:30


Mi directorio actual es C:\Users\arthusu en este directorio se encuentra el archivo 'log.txt'.
Y el resultado que nos arroja es May 02 2014 07:57:30 que es la fecha de la ultima modificacion del archivo.

vamos a explicar el codigo, en la variable $filename especificamos la ruta del archivo que queremos saber su ultima modificacion en este caso 'log.txt' pero tu podrias poner la ruta completa, con la variable $fmtime se guarda la ultima fecha de modificacion el archivo 'log.txt' en formato devuelto como tiempo UNIX, por ultimo hacemos un condicional donde verificamos si el archivo existe y si es asi mostramos la ultima fecha de modificacion en el formato anterior usando la funcion date().

Para agregar una nueva linea en consola usamos \n ya que no podemos usar HTML.

C:\Users\arthusu>php -r "echo \"Hola Mundo!\n\";"
Hola Mundo!



PHP CLI interactivo

Desde la version 5.1, PHP es compilado con una extension Readline la cual podemos correr una shell interactiva. Para utilizar PHP CLI Interactivo solo tenemos que seguir los pasos de abajo.

1.- entramos en modo shell interactiva php -a
2.- escribimos un fragmento pequeño de codigo y presionamos la tecla enter





Tambien podemos ver con php -m que el modulo readline esta activado.






Creamos una variable:



Usted puede crear variables, arrays para su posterior consulta, tal como constantes y funciones todo en una sola sesion.

Tambien si ponemos pri y presionamos la tecla TAB nos autocompleta. Gracias a la extension Readline incluimos muchas caracteristicas tales como tambien usar flecha arriba y flecha abajo para ver las lineas anteriores.

Poniendo exit salimos de la sesion del modo shell interactivo.


Creando un script de linea de comandos

Ser capaz de probar pequeños fragmentos de codigo en la linea de comandos es agradable, pero no te llevara lejos. Lo que normalmente se desea hacer es ejecutar scripts (varias lineas) en la linea de comandos. Tales scripts pueden ejecutar algunos archivos, realizar mantenimiento a una base de datos, ejecutar actualizaciones para el sitio web y demas. Un script para utilizarlo en PHP CLI es diferente a un script de PHP WEB.

1.- No se debe utilizar con codigo HTML
2.- No es necesario utilizar la extension .php (aunque si es recomendable)
3.- La primera linea de su script sera:  #!/usr/bin/php

No hay nada de malo en usar codigo HMTL, pero solo va estorbar en el resultado en la consola. En cuanto a la extesion del archivo podria utilizar literalmente cualquier extension o nombre, pero .php todavia es una buena idea. La ultima linea indica para sistemas MAC OS X o UNIX donde se encuentra el ejecutable de php, esta linea es llamada Shebang, en sistemas Windows no es necesario especificarla ya que es ignorada completamente.

Vamos a crear nuestro primer script de linea de comandos y explicarlo.

#!/usr/bin/php
<?php # Script - numero.php
    /* Esta pagina lee un archivo
    * e imprime el numero de lineas junto al contenido.
    * Este script puede ser usado con PHP CLI
    */

    // El archivo:
    $file = 'c:\users\arthusu\log.txt';
    // Imprimimos un mensaje dentro:
    echo "\nNumerando el archivo llamado '$file' ... ----------------\n\n";
    // Leemos en el archivo:
    $data = file($file);
    // Contador del numero de linea:
    $n = 1;
    // Imprimimos para cada linea:
    foreach($data as $line){
        // Imprimimos el numero y linea del archivo:
        echo "$n $line";
        // Incrementamos le numeor de linea:
        $n++;
    } // Terminamos el bucle foreach.
    echo "\n ------------------------ Fin del archivo '$file'.\n";
?>


  
1.- Especificamos la linea Shebang (aunque realmente no es necesaria si estas en windows), y despues abrimos la etique php (porfin!!!)
2.- Indicamos la ruta del archivo a ser numerado en la variable $file
3.-  Usamos la funcion file() para leer el archivo que se guardara en un array
4.- Imprimimos un mensaje de que el archivo comienza
5.- Creamos una variable $n la cual contendra el numero de lineas, recorremos con el bucle foreach() cada linea y aumentamos la variable $n de la linea en 1 para ir contando las lineas.
6.- Terminamos el mensaje de que el archivo termina, y recuerda aqui si cerramos la etiqueta de php.


Usted puede hacer uso de la configuracion php.ini desde la linea de comandos, una manera de buscar el archivo de configuracion es utilizar:

D:\>php -i | find /i "Configuration File"
Configuration File (php.ini) Path => C:\Windows
Loaded Configuration File => C:\xampp\php\php.ini


o tambien:

php --ini
 

Hay algunas opciones con la que podemos cambiar le comportamiento del archivo php.ini.

* -c Le decimos a php donde buscar el archivo php.ini
* -n Le decimos a php que no utilice el archivo php.ini
* -d Establece un valor para php.ini

Por ejemplo, podemos hacer uso de ignore_user_abort en true para que el script se siga ejecutando incluso cuando el usuario aborte el script, para ello cuando invocamos CLI usamos:

php nombredelscript.php -d  ignore_user_abort=1

Corriendo un script de linea de comandos

Hay dos maneras de correr un script en php. La primera manera es utilizar php y el nombre del archivo a ejecutar:

php nombredelscript.php

tambien podemos utilizar la bandera -f:

php -f nombredelscript.php

aunque no es necesario, pero si recomendable.

La segunda manera de hacerlo que se decia es simplemente utilizar el nombre del archivo, pero para ello tienes que tener configurado windows por ejemplo a abrir por defecto ese tipo de archivo con php.exe:

Clic derecho en el archivo > Abrir con... y eliges el archivo php.exe (en mi caso C:\Xampp\htdocs\php\php.exe), para correr el archivo solo entras en la consola y escribes el nombre del archivo, por ejemplo: miarchivo.php y enter.



Podemos utilizar la opcion -l para saber si algun archivo tiene algun error de sintaxis:

php -l elnombredemiarchivo.php

Si no contiene errores devolvera algo como lo siguiente:
No syntax errors detected in xxxx.php


Trabajando con argumentos en la linea de comandos

El ejemplo numero.php es una aplicacion bastante razonable en PHP CLI. El script proporciona un valioso servicio, pero tiene una limitacion: el archivo a ser numerado en el script esta hard-coded. Seria mejor establecer ese valor del archivo cuando se utiliza la aplicacion. Esto puede lograrse facilmente reescribiendo el script para que utilice argumentos en la linea de comandos. Los argumentos en la linea de comandos son valores pasados en una aplicacion cuando se ejecuta. Los argumentos se pasan a la aplicacion invocada añadiendolos despues del nombre de la aplicacion:

nombredelscript.php argumento1 argumento2

En su script PHP puede acceder a estos argumentos refiriendose a $argv y $argc (o mas formal  $_SERVER['argv'] y $_SERVER['argc'])
El array $argv almacena cada argumento proporcionado; $argc almacena el numero de elementos en $argv. El unico incoveniente a la utilizacion de estos es que el nombre del script en si es el primer argumento listado ($_SERVER['argv'][0]):

#!/usr/bin/php
<?php
    echo "\n{$_SERVER['argc']} argumentos recibidos. Los cuales son...\n";
    foreach ($_SERVER['argv'] as $k => $v) {
        echo "$k : $v \n";
    }
?>



 

Vamos a escribir un nuevo script numero.php para que acepte un argumento: el nombre del archivo a numerar.

#!/usr/bin/php
<?php # numero2.php
    /* Esta pagina lee un archivo
    * e imprime el numero de lineas junto al contenido.
    * Este script puede ser usado con PHP CLI
    * Este script espera un argumento (junto al nombre del script)
    * El numbre del archivo a numerar.
    */


    // Verificamos que el nombre fue asignado:
    if ($_SERVER['argc'] == 2){
    // Obtenemos el nombre del archivo
    $file = $_SERVER['argv'][1];

    // Hay que estar seguros que el archivo existe y es un archivo:
    if(file_exists($file) && is_file($file)){
            // Leemos un archivo:
            if($data = file($file)){
                // Imprimimos un mensaje dentro:
                echo "\n Numerando el archivo llamado '$file' \n ---------------------------\n\n";
                // Contador de lineas
                $n = 1;
                // Imprimimos cada linea:
                foreach ($data as $line) {
                    // Imprimimos el numero y la linea:
                    echo "$n $line";
                    // Incrementamos el numero de linea:
                    $n++;
                } // Fin del bucle foreach
                echo "\n ---------------------------\n Fin del archivo '$file'.\n";
                exit(0);
            }else{
                echo "El archivo no pudo ser leido.\n";
                exit(1);
            }
        } else {
            echo "El archivo no existe \n";
            exit(1);
        }
    } else {
        // Imprimimos el uso:
        echo "\n Uso: numero2.php <archivo>\n\n";
        exit(1);
    }
?>




1.- Comenzamos agregando la linea shebang y nuestra etiqueta de apertura php: 
#!/usr/bin/php
<?php

2.- Verificamos que el archivo fue provisto: if ($_SERVER['argc'] == 2){
3.- Estamos seguros de que el archivo existe:

$file = $_SERVER['argv'][1];
if(file_exists($file) && is_file($file)){

El array argv le pusimos 1 por que en 0 esta el nombre del script que estamos ejecutando actualmente y como segundo argumento nuestro argumento que nos interesa.

4.- Leemos el archivo y lo imprimimos:

if($data = file($file)){
                // Imprimimos un mensaje dentro:
                echo "\n Numerando el archivo llamado '$file' \n ---------------------------\n\n";
                // Contador de lineas
                $n = 1;
                // Imprimimos cada linea:
                foreach ($data as $line) {
                    // Imprimimos el numero y la linea:
                    echo "$n $line";
                    // Incrementamos el numero de linea:
                    $n++;
                } // Fin del bucle foreach
                echo "\n ---------------------------\n Fin del archivo '$file'.\n"
;


5.- Devuelve 0 para indicar la correcta ejecucion del script:
exit(0);

Tipicamente 0 representa que se ejecuto sin problemas y un numero distinto significa algun tipo de error. La funcion exit() termina con la ejecucion del script.

6.- Completamos el condicional del paso 4:

}else{
                echo "El archivo no pudo ser leido.\n";
                exit(1);
            }


7.- Completamos el condicional del paso 3:

} else {
            echo "El archivo no existe \n";
            exit(1);
        }


8.- Completamos el condicional del paso 2 y completamos el script:

} else {
        // Imprimimos el uso:
        echo "\n Uso: numero2.php <archivo>\n\n";
        exit(1);
    }


Para ejecutarlo solo usamos: 

php numero2.php <rutaarchivo>

Creacion de una interfaz

El uso de PHP en linea de comandos, se abre todo un nuevo mundo que en la web no tiene: la interfaz de usuario. Claro que la presentacion de una pagina web es algo diferente se utiliza HTML, pero en linea de comandos no es asi, para comenzar la mayoria de la mayoria de los scripts en lineas de comandos indican como se utilizara, si esta se utiliza incorrectamente. Escriba php -varmit y vera lo que quiero decir. El script numero2.php hace esto pero solo poco, los scripts normalmente hacen mas, como mostrar una opcion para ofrecer ayuda, por ejemplo: con el comando -h o --help.
Por ultimo, las aplicaciones de linea de comandos a menudo arrojan un codigo que indica si la operacion se realizo con exito. El numero 0 es devuelto para indicar que no hubo ningun problema, y algunos numeros distintos a cero devuelven distintas cosas. En numero2.php se devuelve 1 para indicar que hay un error. 
Una alternativa para el uso de argumentos de linea de comandos es solicitar la entrada del usuario (si bien se pueden utilizar ambas tecnicas en combinacion). De esta manera puede crear una aplicacion interactiva, donde se pide al usuario informacion y hace algo con lo que se ingresa. 

Tomandos entradas

Por extraño que pueda parecer, teniendo una entrada (input) en la aplicacion de la linea de comandos es exactamente igual que la lectura de datos desde un archivo. Pero en este caso, en lugar de utilizar un manejador de archivo (un puntero a un archivo abierto) vamos a usar una constante especial STDIN. Esto significa entrada estandar (standard input) lo que seria el teclado por defecto. Una forma facil de leer la entrada estandar seria utilizar la funcion fgets():

echo "Dime algo ";
$input = fgets(STDIN);


 
Todo lo escrito alli por el usuario se asigna a $input. Para ser mas precisos con la entrada, me gusta utilizar la funcion  fscanf(). Como printf() y sprintf(). Esta funcion toma el formato de parametros para manejar tipos especificos de datos. Mediante el uso de esta funcion, en lugar de uno mas generico, nos aseguramos de una validacion basica de los datos leidos. En el siguiente ejemplo, fscanf() se utiliza para crear una aplicacion que convierte temperaturas entre grados Fahrenheit y Celsius (y al reves).

#!/usr/bin/php
<?php # temperatura.php

    /* Esta pagina convierte la temperatura entre
    * Fahrenheit y Celsius.
    * Este script es para utilizarlo en PHP CLI.
    * Este script requiere la entrada (input) de un usuario.
    */

    // Entrada del usuario:
    echo "\nIntroduzca la temperatura e indique si es Fahrenheit o Celsius [##.# C/F]: ";

    // Leemos en una entrada condicional:
    if(fscanf(STDIN, '%f %s', $temp_i, $which_i) == 2){
        // Asumimos una salida invalida:
        $which_o = FALSE;

        // Creamos la conversion basado en $wich_i:
        switch (trim($which_i)) {
            // Celsius, convierte a Fahrenheit;
            case 'C':
            case 'c':
                $temp_o = ($temp_i * (9.0/5.0)) + 32;
                $which_o = 'F';
                $which_i = 'C';
                break;
            // Fahrenheit, convierte a Celsius:
            case 'F':
            case 'f':
            $temp_o = ($temp_i - 32) * (5.0/9.0);
            $which_o = 'C';
            $which_i = 'F';
            break;
        } // Fin del SWITCH.

        // Imprimimos los resultados:
        if($which_o){
            printf("%0.1f %s es %0.1f %s.\n", $temp_i, $which_i, $temp_o, $which_o);
        }else{
            echo "Tu fallaste en poner C o F para indicar el tipo de temperatura.\n";
        }
    }else{ // No puso nada en la entrada
        echo "Tu fallastes en usar la sintaxis correcta.\n";
    } // Fin del IF principal.
   
?>



1.- Comenzamos nuestro script temperatura.php:
#!/usr/bin/php
<?php # temperatura.php

2.- Preguntamos al usuario en que quiere convertir la temperatura:
echo "\nIntroduzca la temperatura e indique si es Fahrenheit o Celsius [##.# C/F]: ";
3.- Leemos un numero con punto y una cadena:
if(fscanf(STDIN, '%f %s', $temp_i, $which_i) == 2){
fscanf() intentara leer en, de la entrada estandar, un numero con punto y una cadena. Estos deben coincidir con la temperatura (por ejemplo, 72.3) y el indicador como el tipo de temperatura (C o F). No hay formato 'caracter' en fscanf(), por lo que con %s son para las cadenas. Si puede leer los tipos de datos en ese orden, que van a ser asignados a las variables. La ultima parte de la funcion fscanf() devolvera el numero de valores que asigna a las variables. Asi que si se lee en dos valores, asignado en $temp_i y $which_i, el condicional sabe que los datos adecuados fueron introducidos.
4.- Establecemos una variable en FALSE.
$which_o = FALSE;
Esta variable almacenara las conversiones de la temperatura (la salida).
5.- Realizamos la conversion apropiada:
switch (trim($which_i)) {
            // Celsius, convierte a Fahrenheit;
            case 'C':
            case 'c':
                $temp_o = ($temp_i * (9.0/5.0)) + 32;
                $which_o = 'F';
                $which_i = 'C';
                break;
            // Fahrenheit, convierte a Celsius:
            case 'F':
            case 'f':
            $temp_o = ($temp_i - 32) * (5.0/9.0);
            $which_o = 'C';
            $which_i = 'F';
            break;
        } // Fin del SWITCH.

Si el segundo valor no es un F, C o f, c la conversion no es impresa.
6.- Imprimimos los resultados:
if($which_o){
            printf("%0.1f %s es %0.1f %s.\n", $temp_i, $which_i, $temp_o, $which_o);
        }else{
            echo "Tu fallaste en poner C o F para indicar el tipo de temperatura.\n";
        }


Usamos printf() para manejar el formato del texto.
7.- Completamos el condicional del paso 3 y el script.
}else{ // No puso nada en la entrada
        echo "Tu fallastes en usar la sintaxis correcta.\n";
    } // Fin del IF principal.
   
?>




Nota: Cualquier funcion de archivo de PHP puede ser usada en STDIN. Esto significa que, por ejemplo, usted podria utilizar fgetc() para recuperar un solo caracter o fgetcsv() para recuperar y analizar una linea entera.

Incorporarlo al servidor

Una adicion en la linea de comandos de PHP 5.4 es un servidor web incorporado. Al usarlo, usted puede probar sus scripts PHP en el navegador web sin necesidad de instalar o ejecutar una aplicacion de servidor web como apache. Para ser absolutamente claro, esto no es un servidor web de produccion, pero puede utilizarse para probar scripts PHP rapidamente.

Para utilizar el servidor web incorporado:

1.- Ponga el siguiente comando para saber si tiene disponible la opcion de servidor web:
php -h
La bandera -h nos lleva a la documentacion de ayuda. Si la documentacion incluye la -S (debe ser mayuscula) y la opcion -t, entonces el servidor incorporado esta disponible.



2.- Navegue hasta el directorio que contiene el script PHP que le gustaria probar:

cd /directorio/a/script

Por defecto, el servidor web usara el directorio en el que el servidor comenzo como el directorio raiz, por lo que usted debe navegar hasta alli primero.

3.- Comenzamos el servidor:

php -S 127.0.0.1:8000

Para iniciar el servidor web utilice la opcion -S, seguido por el nombre de host y el puerto a usar. En su propio ordenador localhost es un nombre de host logico y comun. Para el puerto recomendaria, 8000 o 8080, que son alternativas comunes al puerto por defecto de apache 80. Utilizando uno de estos puertos evita posibles conflictos si ya tiene otro servidor web corriendo. Tambien puede utilizar una direccion IP si lo prefieres:

php -S 127.0.0.1:8000


4.- Cargamos http://127.0.0.1:8000/elnombredetuscript.php en tu navegador web. Como se carga la pagina en el navegador web debes utilizar la linea de comandos CLI, te daras cuenta que la ventana de consola o terminal refleja las solicitudes. 


5.- Pulsa ctrl+C en la consola o terminal para detener el servidor web.


Hasta aqui termina este minitutorial espero que les sirva de ayuda, Saludos!