Source_extract() version2, envío y extracción de datos desde PHP como si fuera un navegador

source extractLos retos se amplían y source_extract() necesitaba un nuevo enfoque para madurar y ser mas versátil, de manera que, frente a la anterior version que solo enviaba POST y usaba Cookies suplantando un navegador, esta nueva version mejora el soporte, permitiendo enviar datos por GET y POST, pudiendo enviar no solo textos si no a demás poder hacer upload de archivos, con opción de mostrar la cabecera HTTP y todo sin perder la opcion de usar cookies. El único problema es que la reestructuración de variables ha echo que no sean igual que en la anterior versión ya que se ha re-escrito casi entera.

[PHP]
function source_extract(
$url,
$POSTdata=”,
$GETdata=”,
$file_upload=”,
$header=false,
$cookie=false
){
$user_agent = ‘Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9′;

#get
if(is_array($GETdata)){
foreach($GETdata as $k => $v){ $GETdata[$k] = $k.’=’.urlencode($v); }
$GETdata = implode(‘&’, $GETdata);
}
if($GETdata!=”) $url .= strpos($url, ‘?’) ? ‘&’.$GETdata : ‘?’.$GETdata;

#post+files
if(is_array($POSTdata)&&!is_array($file_upload)){
foreach($POSTdata as $k => $v){ $POSTdata[$k] = $k.’=’.$v; }
$POSTdata = implode(‘&’, $POSTdata);
} elseif(count($POSTdata)==0){
$POSTdata = array();
}
if(is_array($file_upload)){
foreach($file_upload as $k=>$v){
$v = (substr($v,0,1)!=’.’&&substr($v,0,1)!=’/’) ? ‘./’.$v : ”.$v;
$path_v = realpath(dirname($v));
$file_v = basename($v);
$file_upload[$k] = ‘@’.$path_v.(substr($path_v,-1)!=’/’ ? ‘/’ : ”).$file_v;
}
$file_upload = array_merge($POSTdata, $file_upload);
}

$ch = curl_init($url);
if(is_array($file_upload)|| $POSTdata!=”){
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, (is_array($file_upload) ? $file_upload : $POSTdata));
}
if($cookie){
curl_setopt ($ch, CURLOPT_COOKIEJAR, $cookie);
curl_setopt ($ch, CURLOPT_COOKIEFILE, $cookie);
}
if($header){
curl_setopt ($ch, CURLOPT_HEADER, 1);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (substr($url,0,5)==’https’));
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
$_url_content = $url_content = curl_exec ($ch);
curl_close($ch);
$url_content = array(
‘url’ =>$url,
‘post’ =>$file_upload ? $file_upload : $POSTdata,
‘content’ =>$_url_content
);
if($header){
$_url_content = explode(“\r\n\r\n”, $_url_content,3);

$url_content[‘header’] = (count($_url_content)>2) ? $_url_content[0].”\r\n”.$_url_content[1] : $_url_content[0];

$url_content[‘header’] = explode(“\r\n”, $url_content[‘header’]);
foreach($url_content[‘header’] as $k=>$v){ $o[$k] = explode(‘: ‘, $v,2); $o[$o[$k][0]] = $o[$k][1]; unset($o[$k]); }
$url_content[‘header’] = $o;

$url_content[‘content’] = (count($_url_content)>2) ? $_url_content[2] : $_url_content[1];
}
return $url_content;
}
[/PHP]

El primer parámetro es la URL de referencia donde queremos hacer la consulta o extraer el texto.
El segundo, y tercero son arrays que respectivamente introducen los datos a enviar por POST y GET. En ambos casos se pueden introducir tanto texto en formato campo=valor&campo2=valor o siendo un array en el que las key son los nombres de los campos a enviar y los valores los textos a enviar. Si se pretende enviar algún archivo en la petición es obligatorio que los valores que se envíen por POST estén en formato array.
El cuarto parámetro es un array de archivo/s a subir por POST a la URL de destino. El array debe tener como key los nombres de campo y como valor las direcciones donde se encuentran los archivos. Los archivos tienen que estar dentro del servidor, si se redireccióna alguno externo no se enviará correctamente.
El quinto parametro es un valor boleano de true o false, que tiene false por defecto. Si se pone a true mostrara un valor en el array de salida llamado header que contiene una array de las distintas propiedades devueltas en la consulta HTTP.
El sexto y ultimo parámetro indica la utilización de cookies. Por defecto esta en false para no ser utilizado pero si se le indica la ruta de un archivo, este actúa como un cache de cookies entre consultas almacenando valores entre estas.

Esta vez pondré en otro articulo un ejemplo mas real, por ahora aquí os va un ejemplo para probar todas las propiedades..

Creamos en la misma carpeta un archivo que se llame cookie.txt, y subimos en el mismo sitio una imagen JPG a la que cambiaremos el nombre por “imagen.jpg”. Esta imagen va a ser la que vamos a “transmitir”.
A continuacion creamos otro que se llame receptor.php, y en este escribimos lo siguiente.
[PHP]
$_GET,
‘_POST’ => $_POST,
‘_FILES’ => $_FILES
);
echo ‘////////// FIN DEL CONTENIDO DE LA PAGINA ////////////////////’;
print_r($data);
?>
[/PHP]
Este archivo nos servirá como receptor de la prueba con la que vamos a poder comprobar que datos llegan..

Por ultimo hacemos el código de la pagina propia, con el que vamos a hacer la consulta.
Ponemos el nombre que queramos a la pagina y insertamos el código a continuación.
[PHP]
‘Ejemplo de datos enviados por post’, ‘otro_ejemplo’=>32486245378934);
$get = array(‘ejemplo_get’=>’Ejemplo de datos enviados por get’, ‘otro_ejemplo_por_get’=>37827489237);
$file_upload = array(‘Nombre_de_archivo’=> ‘./imagen.jpg’);
print_r(source_extract($url, $post, $get, $file_upload, true, ‘./cookie.txt’));

/*Esta parte debeis sustituirla por el codigo de la funcion que aparece en la parte de arriba*/
?>
[/PHP]

Hay que tener muy en cuenta que hay q sustituir el ultimo comentario por la función de arriba del todo para que el ultimo archivo se ejecute correctamente.

Cuanto tengamos todo y abramos el ultimo archivo desde el navegador veremos que nos aparecen varios datos entre los que se encontrara la cabecera, un array con todos los datos contenidos de la pagina receptor.php y los datos enviados por post, url…

Pronto tendremos un ejemplo más tangible..
A peticion del publico he realizado una corrección en la linea 78 del código de la función que activa automáticamente el soporte de SSL para las paginas web HTTPS. Si alguien tiene algún problema o incompatibilidad con esa corrección q me lo comente

Apuntes sobre APIs

ApiUna gran necesidad y oportunidad para una herramienta onlie es poder compartir sus potencia de una forma fácil con el resto de la comunidad de desarrolladores para que entre estos puedan usar los datos y capacidades de la aplicación para crear nuevos servicios. Por esto en la web 2.0 es algo totalmente necesario crear una API no solo para que otros servicios puedan acceder al nuestro si no para que inclusive nosotros podamos desarrollar y cambiar la parte gráfica de la aplicación independientemente del código que ofrece el servicio, ofreciendo las mejores prestaciones a los desarrolladores internos y externos. Por esto existen API abiertas que cualquiera puede utilizar y cerradas, que son propias y especificas dentro del servicio.

Ultimamente he visto q toda la web tiene de estas API y que cada una funciona casi de una forma, pero quería reunirme por escrito las igualdades que he ido viendo por si me puede servir en algún proyecto o para crear una propia en algun proyecto..

Al parecer entre varios estándar las web 2.0 prefieren con diferencia usar REST, la cual esta basada en la utilización de los métodos GET, POST, PUT y DELETE para el envío y recepción de información entre el usuario y el servidor, aun que este estándar no se cumple en la mayoría. El estándar primitivo indica que para subir algún archivo se debería usar PUT, y para borrarlos DELETE entre otras funciones reestablecidas, devolviendo siempre los datos en XML. Pero normalmente se usa un sistema con el que están más familiarizados el resto de desarrolladores.
Lo que se suele usar es un sistema mixto que recibe los datos por REST usando FriendlyUrl y GET, y utilizando POST para las modificaciones o para subir archivos.

Esto se suele realizar así por que es muy fácil utilizar un proxy o un programa en el servidor que realce una cache parcial de los datos si estos se pasan dentro de la URL de consulta, y es mas complejo si van acompañados de los datos en la misma cabecera…

En cuanto a las resupuestas de las aplicaciones lo que mas abunda son en XML. es un sistema facil y limpio que es facil de leer por todos los lenguajes en los que se quiera hacer el mashup. Pero el tiempo ha llevado a los creadores de API a poner alternativas con mejor rendimiento para los lenguajes estrella en la web, y casi todas se pueden traducir a jSon, un sistema para mostrar la información mucho mas liviano en aplicaciones JavaScript o PHP. Aunque para la utilización de los datos en PHP, debido a que solo desde la versión 5.0 esta soportado natívamente jSon, algunas API permiten obtener los datos convertidos por serialize() directamente para recogerlos con unserialize() de una forma rápida y liviana.

Como norma general no se suele utilizar la identificación del usuario o el almacenamiento de datos en cookies debido a que seria un obstáculo en algunos lenguajes como también lo seria para el almacenamiento en cache.

Algunos lenguajes de ejemplo:
APIs de las aplicaciones de google | code.google.com
APIs de las aplicaciones de Yahoo | developer.yahoo.com
API de vimeo | www.vimeo.com/api

Como ultimo apunte os dejo un enlace sobre como crear un motor de respuestas REST desde sematopia.com

pag(), paginación de resultados, objetos o paginas en PHP

Función pag()Algo que suele ser repetitivo en la mayoría de proyectos sobre todo si se usan bases de datos o listados de objetos, archivos, arrays… (cosa que en casi todos por no decir en todos se usa) es la paginación. La paginación como todos supongo que sabréis vale para dividir un conjunto de datos muy grande en porciones y poder navegar de esta forma entre los resultados. (si queréis ver un ejemplo solo tenéis que ir a la parte de abajo de google después de hacer una búsqueda).

Después de investigar como hacían otros este proceso me di cuenta que las soluciones mas comunes estaba solo orientadas dentro del PHP a mysql, y integraban no solo el manejo del menú de la pagina si no que a demás cortaban los objetos a mostrar o no mostrar.. cosa que no me interesaba. Yo solo quería el menú, y queria que pudiera valerme no solo para una base de datos, si no para un array o lo q fuera necesario.. :S.

La función que propongo hoy para solucionar esto es pag() la cual lo que hace es a partir de unos datos básicos introducidos como la pagina en la que se quiere estar, el numero de elementos a representar en el menú y el numero de elementos a visualizar por pagina devuelve un array con el contenido personalizado en numero de cada objeto, rango de objetos.. dando opciones a personalizar esta salida o mostrarlo con un simple enlace..

Para meternos en materia os pongo para que vale cada variable de la función por su orden:

  1. Pagina en la que se quiere estar o nombre de la variable GET o POST que va a contener el numero de pagina
  2. Total de objetos que hay en la lista a representar (total de resultados de una consulta, o de un array, o de archivos en una carpeta que queramos representar paginada)
  3. Numero de objetos que queremos que aparezcan en cada pagina
  4. Numero que indica cuantas paginas se ven en el menú generado
  5. Código HTML o texto que acompañará a cada numero.. si está vacio será representado por un enlace simple pero se puede completar con un texto HTML cualquiera. En este texto podemos insertar [p] en cada parte que deseemos que aparezca el numero de pagina. Si se inserta un array con dos textos, el primero corresponderá a los números de pagina normales y el segundo cuando la pagina sea la pagina que se está visitando.
  6. Si se desea incluir el botón “atrás” o “anterior” a partir de esta variable se puede escribir true para que aparezca un botón estándar, false para que no aparezca ningún botón o un texto HTML como en la anterior variable, en el que también se sustituirá [p] por el numero de pagina “anterior”. Si el menú esta situado en la primera pagina no se mostrara este botón.
  7. Idéntico funcionamiento al anterior. Esta variable establece si queremos mostrar el botón de “pagina siguiente”. Como en el anterior false o true lo activan o desactivan y un texto personalizado puede ser establecido como base, siendo sustituido [p]. (este botón no será mostrado si el menú está en el ultimo resultado.)
  8. Esta ultima variable de la función establece si se quiere mostrar un botón que lleva a la ultima pagina. Como en los anteriores, si se quiere activar el modo por defecto que incluye un enlace, solo hay que poner true, si se prefiere que no salga, false y si se quiere personalizar solo hay que poner el texto o código HTML con [p] en las zonas donde se quiere que se escriban el numero correspondiente.

Aquí va el código de la función:
[PHP]
function pag(
$pag_actual = 1, //pagina actual
$total_objetos = 60, //total de objetos a contar
$objetos_por_pagina = 5, //total de objetos por cada pagina
$objetos_por_menu = 5, //números que aparecerán en el menú
$texto_html = ”,
$anterior = true, //poner botón par anterior o texto
$siguiente = true, //poner botón para siguiente o texto
$final = false //poner la ultima pagina

){
#argumentos adicionales para cálculos
$texto_html = $texto_html==” ? array(‘[p]‘, ‘[p]‘) : $texto_html;
$total_paginas = ceil($total_objetos/$objetos_por_pagina); //total de paginas
$mitad_de_objetos_por_menu = round($objetos_por_menu/2); //mitad del menú
$mitad_de_objetos_por_menu_baj = floor($objetos_por_menu/2); //mitad del menú a la baja

#corrección de errores en pagina introducida
if(!is_numeric($pag_actual)){ $pag_actual = $_GET[$pag_actual] ? $_GET[$pag_actual] : $_POST[$pag_actual]; }
if($pag_actual<=0){ $pag_actual = 1; } elseif($pag_actual>$total_paginas){ $pag_actual = $total_paginas; }

if($pag_actual<=$mitad_de_objetos_por_menu){ //detectamos si esta al principio [desde el 1 hasta el $mitad_de_objetos_por_menu] $debug_zone = 'inicio'; $ini = 1; $fin = $objetos_por_menu<$total_paginas ? $objetos_por_menu : $total_paginas; } elseif($pag_actual<=($total_paginas-$mitad_de_objetos_por_menu)){ //detectamos si esta en la zona central [desde el $mitad_de_objetos_por_menu hasta el ($total_paginas-$mitad_de_objetos_por_menu)] $debug_zone = 'medio'; $ini = $mitad_de_objetos_por_menu_baj>$pag_actual ?
$mitad_de_objetos_por_menu_baj-$pag_actual : $pag_actual-$mitad_de_objetos_por_menu_baj;
$fin = $mitad_de_objetos_por_menu_baj+$pag_actual;
} else {
//detectamos si esta al final [desde ($total_paginas-$mitad_de_objetos_por_menu) hasta $total_paginas]
$debug_zone = ‘fin’;
$ini = $total_paginas-$objetos_por_menu+1;
$fin = $total_paginas;
$final = false;
}

//generamos el array de números necesarios para el menú
for($i=$ini;$i<=$fin;$i++){ $out['menu']['pags'][] = $i; $out['menu']['link'][] = '‘.$i.’‘;
if(is_array($texto_html)){
$out[‘menu’][‘html’][] = str_replace(‘[p]’, $i, ($pag_actual==$i ? $texto_html[1] : $texto_html[0]) );
} else {
$out[‘menu’][‘html’][] = str_replace(‘[p]’, $i, $texto_html);
}
}

#determinamos si se puede poner anterior
if($pag_actual!=1 && $anterior){
if($anterior===true){ $anterior = $pag_actual-1; }
$out[‘anterior’] = $pag_actual-1;
$out[‘menu’][‘pags’] = array_merge(array(‘anterior’ => $pag_actual-1 ), $out[‘menu’][‘pags’]);
$out[‘menu’][‘link’] = array_merge(array(‘anterior’ => ‘anterior‘ ), $out[‘menu’][‘link’]); if($siguiente!==true){
$out[‘menu’][‘html’] = array_merge(array(‘anterior’ => str_replace(‘[p]’, $pag_actual-1, $anterior) ), $out[‘menu’][‘html’]);
} elseif($siguiente!==true){
$out[‘menu’][‘html’] = array_merge(array(‘anterior’ => ‘anterior‘ ), $out[‘menu’][‘html’]);
}
} else { unset($anterior); }

#determinamos si se debe poner el max final
if($final){
$out[‘final’] = $total_paginas;
$out[‘menu’][‘pags’][‘final’] = $total_paginas;
$out[‘menu’][‘link’][‘final’] = ‘…’.$total_paginas.’‘;
if($final!==true){
$out[‘menu’][‘html’][‘final’] = str_replace(‘[p]’, $total_paginas, $final);
} elseif($final===true){
$out[‘menu’][‘html’][‘final’] = ‘…’.$total_paginas.’‘;
}
} else { unset($final); }

#determinamos si se puede poner siguiente
if($pag_actual!=$total_paginas && $siguiente){
$out[‘siguiente’] = $pag_actual+1;
$out[‘menu’][‘pags’][‘siguiente’] = $pag_actual+1;
$out[‘menu’][‘link’][‘siguiente’] = ‘siguiente‘;
if($siguiente!==true){
$out[‘menu’][‘html’][‘siguiente’] = str_replace(‘[p]’, ($pag_actual+1), $siguiente);
} elseif($siguiente===true){
$out[‘menu’][‘html’][‘siguiente’] = ‘siguiente‘;
}
} else { unset($siguiente); }

$out[‘ini’] = ($pag_actual*$objetos_por_pagina)-$objetos_por_pagina; //primer objeto de la página
$out[‘fin’] = ($pag_actual*$objetos_por_pagina)-1; //ultimo objeto de la página
return $out;
}
[/PHP]

La función comienza con el supuesto de que la 1º pagina es la pagina 1 (y no la cero) y el primer objeto es el 0 (no el uno) para seguir una correlación lógica entre la parte del código/consulta y la parte de la interfaz del usuario.
Si se encuentra con que la pagina es 0, o menor a 0 la sustituirá por 1 y si se encuentra que la pagina es mayor del numero total de paginas calculadas la sustituirá por la ultima pagina.

Como salida esta función da un array multidimensional que muestra las key ini que corresponde al número del primer objeto de la página, fin que corresponde al número del ultimo objeto de la pagina, y menu que contendrá a su vez en forma de array las tres formas de representación del menú pags (contiene un array con todos los números de pagina resultantes), link (que muestra un menú estándar echo de enlaces) y html (que muestra el menú personalizado a partir de los textos html).
Como opcional en cada punto y según las opciones seleccionadas, pueden aparecer adicionalmente en el array las key anterior, siguiente y final, que contendrían los botones específicos para ir a esas paginas.

Y ahora q sabemos como controlarlo todo y que sale en consecuencia vamos a hacer alguna prueba..

El primer ejemplo es el modo más simple y estático de usar la función. Usaremos los valores por defecto desactivando todos los botones adicionales para que solo aparezca el menú con enlaces estándar.
[PHP]
$menu = pag(
1, //pagina actual
600, //total de objetos a contar
6, //total de objetos a mostrar por cada pagina
10, //numeros que apareceran en el menu
”, //texto personalizado a obtener
false, //poner boton par anterior o texto
false, //poner boton para siguiente o texto
false //poner la ultimapagina
);
echo implode(‘ ‘, $menu[‘menu’][‘link’]).”
\n”;
echo ‘El primer objeto seria el objeto numero ‘.$menu[‘ini’].’, y el ultimo el ‘.$menu[‘fin’];
[/PHP]

El siguiente ejemplo muestra como hacer un menu que usa p como variable GET que determina en que pagina estamos, complementando el código automático. A demás incluye los botones siguiente y anterior. ha sido personalizado para que tenga 50 objetos y muestre 5 en cada pagina, teniendo un menu de 3 numeros
[PHP]
$menu = pag(
‘p’, //pagina actual
50, //total de objetos a contar
5, //total de objetos a mostrar por cada pagina
3, //numeros que apareceran en el menu
”, //texto personalizado a obtener
true, //poner boton par anterior o texto
true, //poner boton para siguiente o texto
false //poner la ultimapagina
);
echo implode(‘ | ‘, $menu[‘menu’][‘link’]).”
\n”;
echo ‘El primer objeto seria el objeto numero ‘.$menu[‘ini’].’, y el ultimo el ‘.$menu[‘fin’];
[/PHP]

El siguiente ejemplo tiene los botones persolanizado para que use la variable GET pagina para determinar en que pagina estamos a la vez que incluye el código HTML de cada botón.
[PHP]
$menu = pag(
‘pagina’, //pagina actual
60, //total de objetos a contar
5, //total de objetos a mostrar por cada pagina
4, //numeros que apareceran en el menu
[p]‘, //texto personalizado a obtener
‘, //poner boton par anterior o texto
‘, //poner boton para siguiente o texto
false //poner la ultimapagina
);
echo implode(‘ | ‘, $menu[‘menu’][‘link’]).”
\n”;
echo ‘El primer objeto seria el objeto numero ‘.$menu[‘ini’].’, y el ultimo el ‘.$menu[‘fin’];
[/PHP]

Como ultimo ejemplo vamos a hacer que muestra la misma estructura del anterior pero a demás, discrimina la pagina actual en el menu, y no le pone enlace para que se pueda diferenciar..
[PHP]
$menu = pag(
‘pagina’, //pagina actual
60, //total de objetos a contar
5, //total de objetos a mostrar por cada pagina
4, //numeros que apareceran en el menu
array( //texto personalizado indicando cuando es la pagina actual
[p]‘,
[p]
),
‘, //poner boton par anterior o texto
‘, //poner boton para siguiente o texto
false //poner la ultimapagina
);
echo implode(‘ | ‘, $menu[‘menu’][‘link’]).”
\n”;
echo ‘El primer objeto seria el objeto numero ‘.$menu[‘ini’].’, y el ultimo el ‘.$menu[‘fin’];
[/PHP]

Que lo disfrutéis..

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.