Función de extracción de datos Youtube() en PHP version3

Youtube()A estas alturas supongo que los que lean este blog seguramente sepan que hace esta función. Es una función que a partir de una ID de youtube extrae el resto de datos del mismo video…
El motivo de esta actualización es el aviso de @pablo que me indicaba que en la versión 1 se la función si que se obtener el usuario que ha subido el video, asi que esa ha sido la primera corrección.
Revisando el código a demás me di cuenta que la fecha también fallaba, así como el debug de fecha, y como guinda.. mucha gente esta usando la direccion de youtube completa para obtener el ID y para los usuarios menos expertos es un coñazo el extraerlo.. así que he incorporado el metodo que el genio Alex Barros diseño en Boozox y uno de sus lectores @Javier compartieron para que ahora podamos ver los vídeos no solo con la ID si no que también con la URL.

[PHP]
function youtube($id, $debug = false) {
$_id = parse_url($id);
parse_str($_id[‘query’]);
unset($_id);
$id = empty($v) ? $id : $v;

$url = ‘http://es.youtube.com/watch?v=’.$id;
$query = @file_get_contents($url);

$exp_info = ‘!&t=(.+)&!U’;
preg_match_all($exp_info,$query,$t);

$exp_info = “!!U”;
preg_match_all($exp_info,$query,$titulo);

$exp_info = “!!U”;
preg_match_all($exp_info,$query,$descripcion);

$exp_info = “!(.+) de (.+) de (.+)!U”;
preg_match_all($exp_info,$query,$fecha);

$exp_info = ““;
preg_match_all($exp_info,$query,$tags);

$exp_info = “!href=\”/user/(.+)\”!U”;
preg_match_all($exp_info,$query,$user);

$t = $t[1][0];
$titulo = $titulo[1][0];
$descripcion = $descripcion[1][0];
$fecha = ($fecha[1][0]&&$fecha[2][0]&&$fecha[3][0]) ? $fecha[1][0].’ de ‘.$fecha[2][0].’ de ‘.$fecha[3][0] : ”;
$tags = $tags[1][0];
$user = $user[1][0];

$salida[“id”] = $id;
$salida[“t”] = $t;
$salida[“url”] = $url;
$salida[“iurl”] = “http://img.youtube.com/vi/”.$id.”/2.jpg”;
$salida[“reproductor”] = “http://www.youtube.com/p.swf?video_id=”.$id.”&iurl=http://img.youtube.com/vi/”.$id.”/2.jpg&t=”.$t;
$salida[“video”] = “http://youtube.com/get_video.php?video_id=”.$id.”&t=”.$t;
$salida[“html”] = ““;
$salida[“title”] = $titulo;
$salida[“descripcion”] = $descripcion;
$salida[“fecha”] = $fecha;
$salida[“tags”] = $tags;
$salida[“usuario”] = $user;

if($debug){
//sistema de diagnostico
$salida[‘debug’] = $query;
$s[‘la url de lectura es’] = $url;
$s[‘lectura de video’] = ($query ) ? ‘si’ : ‘no’ ;
$s[‘t encontrado’] = ($t ) ? ‘si’ : ‘no’ ;
$s[‘titulo encontrado’] = ($titulo ) ? ‘si’ : ‘no’ ;
$s[‘descripcion encontrada’] = ($descripcion ) ? ‘si’ : ‘no’ ;
$s[‘fecha encontrada’] = ($fecha ) ? ‘si’ : ‘no’ ;
$s[‘tags encontrados’] = ($tags ) ? ‘si’ : ‘no’ ;
$s[‘usuario encontrado’] = ($user ) ? ‘si’ : ‘no’ ;
$s[‘contenido para debug’] = $salida;
return $s;
}
if($t == “”){ //Error de conexion
return false;
} else { // todo OK
return $salida;
}
}
[/PHP]

Un ejemplo con ID:
[PHP]
$datos = youtube(‘aWCD69urAqQ’);
print_r($datos);
[/PHP]

El mismo ejemplo de antes pero esta vez con la URL completa:
[PHP]
$datos = youtube(‘http://es.youtube.com/watch?v=aWCD69urAqQ&fmt=18’);
print_r($datos);
[/PHP]
He sacado una nueva version que corrige errores de peticion y caracteres. la podeis encontrar en Función de extracción de datos Youtube() en PHP version4

Lectura de archivos MO de GetText y simplificación de su uso con PHP

rosetta diskQue el mundo cada día es un lugar mas cercano y global es algo cada vez mas palpable, y que las traducciones de nuestras paginas son algo igualmente importante también es algo que cualquiera puede ver, así que últimamente he estado viendo como funcionan los sistemas de traducción que suelen usarse en uno de mis lenguajes de programación favoritos, el PHP. Y lo que he visto es que lo mas facil y rapido de usar es el sistema libre GetText.

Este sistema permite internacionalizar a partir de frases, que son buscadas par a par dentro de un archivo precomprimido. Este tipo de archivos son los de extensión MO, generados a partir de archivos que contienen los datos en texto plano (archivos con extensión PO).

Para que no se nos haga pesado usarlo he construido una función que simplifica bastante el trabajo.. se trata de la función gettext_simply().
Directorios de GetText en el FTPPara realizar traducciones correctamente tenemos que en primer lugar crear un árbol de directorios específico para nuestro proyecto. Esto quiere decir que tenemos que crear una carpeta que contenga las diferentes carpetas de lenguajes, (por defecto, lenguajes). Luego cada lenguaje debe tener una nomenclatura especifica indicada por el estándar ISO639, lo que quiere decir, si tu lenguaje es español e España, el código será es_ES, en cambio si es español de Argentina será es_AR
Dentro de esta carpeta debe haber una segunda carpeta llamada LC_MESSAGES y dentro de esta el archivo MO de traducción. Al final el directorio debería quedar como el de la derecha.. (lo de los archivos .PO es una manía mía para mantener el contenido ordenado para futuras actualizaciones..)

Una vez echo el árbol de directorios ejecutamos gettext_simply() para decidir con que archivo vamos a funcionar..
La función de gettext_simply() es la siguiente:
[PHP]
function gettext_simply($lang=’es_ES’, $mo_file=’traduccion’, $path_LC=’./lenguajes’, $debug=false){
$locale = setlocale(LC_ALL, $lang);
$deb[‘locale’] = $locale;
$deb[‘bindtextdomain’] = bindtextdomain($mo_file, $path_LC);
$deb[‘textdomain’] = textdomain($mo_file);
return $debug ? $deb : $locale;
}
[/PHP]

El primer valor es el acrónimo del lenguaje a usar (el nombre del primer directorio..).
El segundo, el nombre del archivo de traducciones, en nuestro caso y por defecto, traduccion.
El tercero, la localización del directorio que contiene las carpetas de lenguajes.
Y por ultimo lugar una variable boleana para ver si queremos la información de los diferentes pasos

Si usamos el mimo arbol de directorios del ejemplo de arriba y el mismo nombre en los archivos MO, cambiar el idioma de una pagina es realmente sencillo…
Para cambiar el idioma de una frase usamos la funcion _().
Aqui os dejo unos cuantos ejemplos de como traducir una frase simple “We cannot find a title on that page.” (teniendo esta frase traducida en los archivos MO necesarios y la estructura de directorios necesaria..)
[PHP]
//traduccion a español simple
gettext_simply(‘es_ES’);
echo _(‘We cannot find a title on that page.’);

//traduccion a argentino
gettext_simply(‘es_AR’);
echo _(‘We cannot find a title on that page.’);

//Carpetas personalizadas, nombres personalizados…
gettext_simply(‘es_ES’, ‘frases’, ‘/mis_idiomas_personalizados’);
echo _(‘We cannot find a title on that page.’);

gettext_simply(‘en_GB’, ‘frases’, ‘/mis_idiomas_en_ingles’);
echo _(‘We cannot find a title on that page.’);
[/PHP]

Otra de mis inquietudes al usar los archivos MO era que no se podían leer en tipo array, de manera que no se podía saber si una traducción existía a simple vista o contar cuantas traducciones hay cargadas..
Al buscar alguna respuesta por Google parece que lo que mas se usa es la clase PHP-Gettextque según vi es la misma que usa wordpress, y me aprecio un poco engorrosa, así que también me decidí a crear una función que lea simplemente los MO convirtiéndolos en array (alguien adivina como la he llamado?) la funcion es mo2array().
La función es simple.. se le introduce la dirección de un archivo .MO y da como resultado un array con todo el contenido del archivo estructurado.
[PHP]
function mo2array($archivo = ‘traduccion.mo’){
$file = file_get_contents($archivo, FILE_BINARY);

$i[‘magic’] = deco(substr($file, 0, 4), true); // extraigo el numero magico para verificar si es valido
if($i[‘magic’] != ‘DE 12 04 95’){ return array(‘error’=>’Archivo no valido, no contiene datos validos de internacionalizacion.’, ‘magic’=>$i[‘magic’]); }
$f=4; $ini=4;
$i[‘version’] = deco(substr($file,$ini,4),’d’); $ini+=$f;
$i[‘len’] = deco(substr($file,$ini,4),’d’); $ini+=$f; //total de frases traducidas
$i[‘ini_original’] = deco(substr($file,$ini,4),’d’); $ini+=$f;
$i[‘ini_traduccion’] = deco(substr($file,$ini,4),’d’); $ini+=$f;
$i[‘len_hash’] = deco(substr($file,$ini,4),’d’); $ini+=$f;
$i[‘ini_hash’] = deco(substr($file,$ini,4),’d’);

$o = str_split( substr($file, $i[‘ini_original’], $i[‘ini_traduccion’]), 4);
$t = str_split( substr($file, $i[‘ini_traduccion’], $i[‘ini_hash’] ), 4);

for($k=1; $k<=$i['len']; $k++){ if($k%2!=0){ #$i['table'][$k ]['o'] = substr( $file, deco($o[$k],'d'), deco($o[$k-1],'d') ); #$i['table'][$k ]['t'] = substr( $file, deco($t[$k],'d'), deco($t[$k-1],'d') ); $i['table'][substr( $file, deco($o[$k],'d'), deco($o[$k-1],'d') )] = substr( $file, deco($t[$k],'d'), deco($t[$k-1],'d') ); } } return $i; } function deco($data, $jumps=false){ //pasa el contenido binario a HEX y lo preformatea if($jumps==='h'){ $o = explode(' ', wordwrap(strtoupper(bin2hex($data)), 2, " ", 1) ); $o = $o[3].$o[2].$o[1].$o[0]; } elseif($jumps==='d'){ // bin2dec $o = explode(' ', wordwrap(strtoupper(bin2hex($data)), 2, " ", 1) ); $o = hexdec($o[3].$o[2].$o[1].$o[0]); } elseif($jumps===true){ $o = wordwrap(strtoupper(bin2hex($data)), 2, " ", 1); } else { $o = strtoupper(bin2hex($data)); } return $o; } [/PHP] La función mo2array() usa una segunda función de apollo llamada deco() que convierte entre material binario, hexadecimal y decimal..
En la salida de mo2array() puede dar un valor con key error si el archivo no ha sido encontrado o no es un archivo PO valido.. si todo va bien da como resultado varios valores de la estructura interna del archivo y un valor tabla, que contiene como keys en las traducciones originales, y como valores de esas key las traducciones resultantes.

Un ejemplo simple:
[PHP]
print_r( po2array(‘./lenguajes/es_ES/LC_MESSAGES/traduccion.mo’) );
[/PHP]

Para crear tu propio grupo de archivos PO y MO hay una infinidad de articulos que hablan sobre ello.. el programa mas utilizado es PoEdit y si solo quieres probar esto puedes experimentar con los que ya hay por la red.

pass_protect(), protege con contraseña cualquier directorio desde PHP

seguridadSeguramente en lo primero que piense cualquiera que quiera proteger algún archivo en internet es ese complejo sistema de bases de datos, archivos encriptados etc etc.. pero Apache nos permite hacer esto de una forma mucho mas sencilla y mezclandolo con PHP la cosa se pone 100 veces mas fácil..

Cuando queramos poner contraseña a una de las carpetas del servidor para que solo se pueda ver las paginas que contiene si se sabe la contraseña podemos usar pass_protect() una sola vez, o reutilizarla para reescribir el usuario y/o contraseña.
Para hacer esto solo tenemos que introducir en el primer lugar un nombre de usuario (o varios en formad e array), en segundo lugar una contraseña (o varias) y por ultimo (opcionalmente) un texto que aparecerá cuando no se sepa la contraseña, (el texto de la tercera variable no puede contener comillas).

Y ahora una tanda de ejemplos:
Si el nombre de usuario y la contraseña no son array, se asignarán haciendo un par natural (nombre de usuario – contraseña).
[PHP]
$name = ‘nombreusuario’;
$pass = ‘SeCrEtO’;
pass_protect($name, $pass);
[/PHP]

Si los valores de nombre y contraseña son array cada valor del array se emparejara haciendo un par (usuario-contraseña), con la excepción de que si uno de los dos no tiene suficientes valores, no se contaran como pares…
[PHP]
$name = array(‘nombre_1’, ‘nombre_2’, ‘nombre3’);
$pass = array(‘SeCrEtO_1’, ‘SeCrEtO2’, ‘SeCrEtO_3’, ‘contraseña_nula’);
pass_protect($name, $pass);
[/PHP]

Si los valores de nombre son array y la contraseña no, se emparejaran todos los nombres de usuario con la misma contraseña.
[PHP]
$name = array(‘nombre_1’, ‘nombre_2’, ‘nombre3’);
$pass = ‘SeCrEtO_unico’;
pass_protect($name, $pass);
[/PHP]

Si los valores de contraseña son array y solo hay un nombre de usuario, se asignara el mismo nombre de usuario con varias contraseñas.
[PHP]
$name = ‘nombredeusuario’;
$pass = array(‘SeCrEtO_1’, ‘SeCrEtO2’, ‘SeCrEtO_3’);
pass_protect($name, $pass);
[/PHP]

Por ultimo un ejemplo simple con modificación del mensaje..
[PHP]
$name = ‘nombredeusuario’;
$pass = ‘SeCrEtO’;
$mensaje = ‘No esta permitido entrar aquí sin autorización, pide una en juanito@algo.com’
pass_protect($name, $pass);
[/PHP]

y aquí os dejo la función:
[PHP]
function pass_protect($name, $pass, $msg=’Area solo para usuarios registrados’){
$files[‘.htaccess’] = array(
‘AuthName “‘.$msg.'” ‘,
‘AuthType Basic ‘,
‘AuthUserFile ‘.realpath(‘./’).’/.htpasswd ‘,
//’AuthGroupFile /dev/null ‘,
‘require valid-user ‘
);
if(is_array($name) && is_array($pass)){ //si ambos son array
foreach($name as $k => $v){
if( !empty($name[$k]) && !empty($pass[$k]) ){ $files[‘.htpasswd’][] = $name[$k].’:’.crypt($pass[$k]); }
}
} elseif(is_array($name)){ foreach($name as $k => $v){ $files[‘.htpasswd’][] = $v.’:’.crypt($pass); } //si el nombre es una array
} elseif(is_array($pass)){ foreach($pass as $k => $v){ $files[‘.htpasswd’][] = $name.’:’.crypt($v); } //si el pass es un array
} else { $files[‘.htpasswd’][] = $name.’:’.crypt($pass); //si nunguno es un array
}

foreach($files as $filename => $cont){
$cont = implode(“\n”, $cont);
$fp = fopen($filename, ‘w+’);
$read = fwrite($fp, $cont, strlen($cont));
fclose($fp);
}
return true;
}
[/PHP]
que la disfrutéis..

source_extract(), extrae el código fuente aun que tengan verificación por cookie

icon source_extractCasi todos los foros, webs 2.0 y demás paginas actuales tienen registros. Y muchas de estas webs solo permiten el acceso o lectura de los datos a partir de estos registros, por esto hoy os dejo esta función.
La función source_extract() es una encapsulación de la función curl, la cual permite enviar y recibir contenido por http, ftp…. en nuestro caso solo tendremos que indicarle 3 parámetros.
El primero es la dirección de la web a extraer, el siguiente es una dirección en el servidor con un nombre de archivo en el que se puedan guardar las cookies necesarias para almacenar los datos recibidos de la web consultada, y el tercero son datos en POST a enviar.

Utilizando esta función podremos mantener una cookie a lo largo de varias consultas como si de un navegador se tratara, de echo la función envía datos emulando ser un navegador firefox en un windows NT (algunas web detectan si es un navegador o no el que accede para permitir el envío de datos). De esta manera podemos acceder a una web, ingresar nuestros datos y realizar tareas en su interior de manera natural y automatizada.

un ejemplo rápido:
[PHP]
$codigo = source_extract(‘http://www.ejemplo.com/wp-admin’, ‘./cookie.txt’);

//codigo ahora mostraría el panel para introducir los datos
$user = ‘paquito84’;
$pass = ‘sEcReTo_123’;
$post = ‘log=’.$user.’&pwd=’.$pass;
$codigo = source_extract(‘http://www.ejemplo.com/wp-admin’, ‘./cookie.txt’, $pos);
//en esta consulta en $codigo nos mostrará el panel de administración

$codigo = source_extract(‘http://www.ejemplo.com/wp-admin/post-new.php’, ‘./cookie.txt’, $pos);
//y ahora si q podríamos inclusive ver la pagina de nuevo post
print_r($codigo);
[/PHP]

y el código completo..
[PHP]
function source_extract($file, $cookie, $postdata = ”){
$user_agent = ‘Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9’;
$ch = curl_init($file);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_COOKIEJAR, $cookie);
curl_setopt ($ch, CURLOPT_COOKIEFILE, $cookie);
curl_setopt ($ch, CURLOPT_USERAGENT, $user_agent);
if($postdata!=”) curl_setopt ($ch, CURLOPT_POSTFIELDS, $postdata);
curl_setopt ($ch, CURLOPT_POST, 1);
$file_content = curl_exec ($ch);
curl_close($ch);
return $file_content;
}
[/PHP]

El ejemplo anterior es un código para ver como se podría componer una consulta con datos ficticios, pero prometido que para el próximo post traigo algo más interesante y real… 😉

Actualización que mejora las capacidades de la función.

Reconocimiento facial en imágenes con PHP y OpenCV

OpenCVHoy no toca algo de mi propia cosecha, pero este echo no le quita espectacularidad al asunto..
Seguro que muchos habéis visto u oído hablar del tema del reconocimiento facial en imágenes o explicado claramente, el sistema que detecta donde esta la cara de la gente en una imagen o video por las recientes modificaciones en el buscador de Google y Picasa. Anteriormente este era un terreno que solo dominaba Riya(ahora bastante abandonada), pero pronto salieron muchas aplicaciones como PolarRose o Picollator abriendo camino a las aplicaciones para esta nueva tecnóloga de búsqueda y comparación mas “humana”.

Reconocimiento de carasPues bien si ahora quieres tu seguir los pasos de esta gente lo podemos conseguir gracias a varios proyectos libres pero el que nos va a servir para usarlo con PHP va a ser OpenCV desarrollado por Intel.

OpenCV es una librería que se encarga de reconocer caras, cuerpos, gestos… a partir de archivos XML que controlan y afinan los resultados.

Para poder utilizar esto en nuestros proyectos seguiremos las instrucciones de xarg.org.

Para instalar la librería correctamente en PHP:

  • Instalar OpenCV (OpenCV 1.0.0)
  • Download facedetect source package
  • Descomprimir el archivo de codigo facedetect
  • Ir a la carpeta facedetect desde la consola y escribir phpize && ./configure && make && make install
  • Comprobar que tengamos extension=facedetect.so en el archivo php.ini

Para compilar las instrucciones dentro de PHP directamente:

  • Instalar OpenCV (OpenCV 1.0.0)
  • Download facedetect source package
  • Descomprimir el archivo de codigo facedetect en $PHP_SOURCE_DIR/ext/facedetect
  • En el directorio raiz del codigo PHP ejecutar en la linea de comandos: rm configure && ./buildconf --force
  • Configurar PHP con el comando ./configure --with-facedetect
  • Ejecutar make && make install

(Para que todas las funciones de OpenCV funcionen correctamente necesita tener instalado en el sistema: pkgconfig, libpng, zlib, libjpeg, libtiff y python).

Una vez realizado eso tendremos dos nuevas instrucciones en nuestro lenguaje PHP instaladas.
Estas dos funciones son face_count() y face_detect() que respectivamente detectan cuantas caras hay en una imagen y donde están esas caras.

El metodo de utilizacion de ambas dunciones es realmente sencillo, solo tenemos que introducir como primer parámetro una imagen y como segundo el archivo XML suministrado por OpenCV o generado por nosotros a partir de su documentación para definir el tipo de detección:
[PHP]
print_r(face_count(‘party.jpeg’, ‘cascade.xml’));
print_r(face_detect(‘party.jpeg’, ‘cascade.xml’));
[/PHP]

Al no tener un servidor propio para experimentar todavía no he podido comprobar los pasos así que si alguien quiere confirmar que todo funciona correctamente seria todo un detalle que lo comentarais por aquí para comprobar que funciona.