Foros del Web » Programando para Internet » PHP »

Optimizar este script -- Ayuda Por Favor -

Estas en el tema de Optimizar este script -- Ayuda Por Favor - en el foro de PHP en Foros del Web. Hola. Hace tiempo postee un mensaje sobre un script para manejar enlaces recíprocos q estaba realizando en php. Tras la ayuda proporcionada por algunos de ...
  #1 (permalink)  
Antiguo 13/01/2003, 08:37
 
Fecha de Ingreso: diciembre-2002
Mensajes: 23
Antigüedad: 21 años, 11 meses
Puntos: 0
Optimizar este script -- Ayuda Por Favor -

Hola. Hace tiempo postee un mensaje sobre un script para manejar enlaces recíprocos q estaba realizando en php. Tras la ayuda proporcionada por algunos de vosotros llegué a la actual composición, pero el script no puede manejar grandes cantidades de enlaces.

La idea es proporcionarle un listado de enlaces, que saque las url y el nombre de los enlaces, y q compruebe q en cada url proporcionada existe un enlace determinado. Esto lo hago abriendo la página y leyendo línea por línea hasta encontrar el enlace. El problema, como ya he mencionado es q no puede con más de 100 enlaces aprox.

Les posteo el código, para ver si pueden aconsejarme como optimizar el mismo. Gracias por su tiempo.

Código PHP:
<?php 
if (getenv('REQUEST_METHOD') == 'POST') { 
  
$url $_POST[url]; 
  
$reciproco $_POST[reciproco];
} else { 
  
$url $_GET[url]; 
  
$reciproco $_GET[reciproco];

?> 

<form action="<?= $PHP_SELF ?>" method="POST">
  <div align="center">
    <table width="75%" border="0" cellspacing="5" cellpadding="0">
<tr>
        <td width="12%">URL:</td>
        <td width="88%"> <input name="url" type="text" value="<?= $url ?>" size="80"/></td>
      </tr>
      <tr>
        <td>Texto:</td>
        <td><input name="reciproco" type="text" value="<?= $reciproco ?>" size="80"/></td>
      </tr>
    </table>
<input type="submit">
  </div>
</form> 

<?php

  set_time_limit
(0);  
  
// Función para comprobar si existe un determinado texto (enlace) en una url
function recip($surl,$reciproco){
    
$fd fopen ("$surl""r");
    while (!
feof ($fd)) 
    {
        
$buffer fgets($fd4096);
        if (
strstr($buffer,$reciproco))
            return 
true;
    }
    
fclose ($fd);
}

//Borramos de un array los elementos que tengan reciproco
function borrar(&$ahrefs,&$alinks,$reciproco){
    
$x=0;    
    while(
$x<sizeof($ahrefs))
    {
    if (
recip($ahrefs[$x],$reciproco) == true){
        
array_splice($ahrefs,$x,1);
        
array_splice($alinks,$x,1);}
    else
        
$x++; 
    }
}

  
// Separamos el código html (hrefs y links) 
  
if ($url) { 
  
$remote fopen($url'r'); 
  
$data fread($remote1048576); 
  
fclose($remote); }

  unset(
$location); 
  
$links = array();  // Array con la descripción de los links 
  
$hrefs = array();  // Array de urls
  
$pos 0
  while (!((
$pos strpos($data,"<",$pos)) === false)) { 
    
$pos++; 
    
$endpos strpos($data,">",$pos); 
    
$tag substr($data,$pos,$endpos-$pos); 
    
$tag trim($tag); 
    if (isset(
$location)) {  // Buscamos </A> 
      
if (!strcasecmp(strtok($tag," "),"/A")) { 
        
$link substr($data,$linkpos,$pos-1-$linkpos); 
        
$links[] = $link
        
$hrefs[] = $location
        unset(
$location); 
      } 
      
$pos $endpos+1
    } else {  
// Buscamos <A ...> 
      
if (!strcasecmp(strtok($tag," "),"A")) { 
        if (
eregi("HREF[ \t\n\r\v]*=[ \t\n\r\v]*\"([^\"]*)\"",$tag,$regs)); 
        else if (
eregi("HREF[ \t\n\r\v]*=[ \t\n\r\v]*([^ \t\n\r\v]*)",$tag,$regs)); 
        else 
$regs[1] = ""
        if (
$regs[1]) {  
          
$location $regs[1]; 
        } 
        
$pos $endpos+1
        
$linkpos $pos
      } else { 
        
$pos $endpos+1
      } 
    } 
  } 
  
borrar($hrefs,$links,$reciproco);
for (
$i=0$i<sizeof($links); $i++) { 
    echo 
"<A HREF=\"".$hrefs[$i]."\">".$links[$i]."</A><BR>\n"
  } 
?>
  #2 (permalink)  
Antiguo 13/01/2003, 09:08
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 10 meses
Puntos: 129
Lo que tienes que hacer es optimizar el uso de las Expresiones regulares q usas ..

En PHP tienes las expresiones regulares compatibles con Perl como preg_match_all() .. Justo uno de los ejemplos que hay hace lo que buscas tan solo con esa función y un buen uso de la expresión regular obtienes un array bidimensinal con toda las conincidencias de tu mascara usada.

http://www.php.net/manual/en/functio...-match-all.php

Un saludo,

Pd: si mal no recuerdo yo mismo te indiqué esto en el anterior mensaje que haces mención....
  #3 (permalink)  
Antiguo 13/01/2003, 15:20
 
Fecha de Ingreso: diciembre-2002
Mensajes: 23
Antigüedad: 21 años, 11 meses
Puntos: 0
Gracias cluster. La expresión q me comentas funciona a la perfección pero ese no es el problema. Si te fijas, la separación de url y enlace sólo se hace una vez, por lo q el consumo de recursos es mínimo. El problema creo q está en la forma de comprobar el recíproco.

Código PHP:
function recip($surl,$reciproco){
    
$fd fopen ("$surl""r");
    while (!
feof ($fd)) 
    {
        
$buffer fgets($fd4096);
        if (
strstr($buffer,$reciproco))
            return 
true;
    }
    
fclose ($fd);

De esta forma, para cada página enlazada leemos línea a línea hasta q encontremos el enlace. Pero para listas muy largas parece q se colapsa.

¿Alguna idea sobre como reducir el coste? ¿Podría usar exp. regulares aquí para reducir la carga?

Un saludo a todos, y gracias por la ayuda.
  #4 (permalink)  
Antiguo 13/01/2003, 16:06
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 10 meses
Puntos: 129
La funcion q te mencioné hace todo el proceso q requiers de una vez sobre un string (cadena de caracteres) .. lo q tendrias q hacer es volcar ese archivo hacia un string y no hacia un array para leerlo uno a uno (linea a linea) para poder usar correctametne la funcion q te mencioné.

con

readfile() lees un archivo hacia el buffer de salida .. si lo asignas a una variable .. ya lo tienes en un string:

$archivo_entero=readfile("archivo.tal");

y luego aplicarle la función .. Pruebalo y nos comentas.

Un saludo,
  #5 (permalink)  
Antiguo 13/01/2003, 17:25
 
Fecha de Ingreso: diciembre-2002
Mensajes: 23
Antigüedad: 21 años, 11 meses
Puntos: 0
Nada, q atascado estoy. He usado readfile() como me has dicho, pero al mandarlo al buffer de salida, carga las webs de los enlaces en cada llamada.

Lo he hecho así:

Código PHP:
if (strstr(readfile($surl),$reciproco)!=false
return 
true
Al tener q buscar un enlace determinado (el recíproco) no creo q me haga falta el uso de expresiones regulares. Pero de poder usarse, si hiciese un preg_match_all me devolvería un string con las apariciones. ¿Debería comprobar si el array está vacio?.

Una ayudita pls! Y gracias por la tuya Cluster!
  #6 (permalink)  
Antiguo 13/01/2003, 17:30
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 10 meses
Puntos: 129
Pero te dije que el readfile() lo asignases a una variable:

Código PHP:
$nose=readfile($url);
if (
strstr($nose,$reciproco)!=false
return 
true
Un saludo,
  #7 (permalink)  
Antiguo 13/01/2003, 18:44
 
Fecha de Ingreso: diciembre-2002
Mensajes: 23
Antigüedad: 21 años, 11 meses
Puntos: 0
Pasa exactamente lo mismo Cluster. Por cada enlace manda la página a la salida (la pantalla). Así q ni idea!
  #8 (permalink)  
Antiguo 13/01/2003, 19:46
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 10 meses
Puntos: 129
Ok, creia que podriamos usar el readfile() como decia .. pero no es así .. una opcion es usar el mismo file() pero con un implode() para generar un string con los elementos del array concatenados por '' (nada, ningun caracter uno tras otro).

$nose = implode ('', file ($url));

Un saludo,
  #9 (permalink)  
Antiguo 13/01/2003, 20:14
 
Fecha de Ingreso: diciembre-2002
Mensajes: 23
Antigüedad: 21 años, 11 meses
Puntos: 0
Gracias de nuevo cluster.

Con implode ya había probado al leer el ejemplo de php.net. De esta forma:
Código PHP:
$contents implode(""file($surl));
    if (
strstr($contents,$reciproco)!=false)
    return 
true
Para ver si ganaba velocidad, he calculado la velocidad del proceso para un archivo de 10 links, pero incluso el anterior es más rápido, aunq la diferencia es mínima (+- 1 sg). ¿Quizás con el preg_match_all sería más rápido? Si es así, ¿cómo lo monto?.

Salu2!
  #10 (permalink)  
Antiguo 13/01/2003, 21:38
 
Fecha de Ingreso: diciembre-2002
Mensajes: 23
Antigüedad: 21 años, 11 meses
Puntos: 0
Creo q he encontrado el problema del q parte todo. El script se queda colgado cuando entre los enlaces proporcionados hay algunos q o no respoden o tardan mucho en responder a la llamada.

Por lo tanto ahora me asalta otro problema. Podría chequear el estado de las urls (ni idea de como). Podría poner un time determinado para abrir una url, pasado el cual pasase a la siguiente. Pero hay un problema, y es q al ser secuencial, si pongo un timeout de 30 y hay 5 enlaces q van mal pues ya son 150 seg de espera. Tampoco tengo idea de si se puede poner un timeout a un fopen.

Bueno Cluster. Ante todo, mil gracias por la ayuda, y ya q parece q estamos sólos, se te ocurre algo. Un saludo!
  #11 (permalink)  
Antiguo 13/01/2003, 22:57
O_O
 
Fecha de Ingreso: enero-2002
Ubicación: Santiago - Chile
Mensajes: 34.417
Antigüedad: 22 años, 10 meses
Puntos: 129
Para la optimización del código .. como te mencioné desde un principio .. usando preg_match_all():

Código PHP:
<?
$url 
"http://www.php.net/manual/es/";
$html Implode(""File($url));

preg_match_all("/<a[[:space:]]+href[[:space:]]*=[[:space:]]*[\"']{0,1}([^\"'> ]+)/i",$html,$links_url,PREG_SET_ORDER);

preg_match_all("|>([^<]*)</a|i",$html,$links_descripcion,PREG_SET_ORDER);

for (
$i=0;$i<count($links_url);$i++){
echo 
"<A HREF=\"".$links_url[$i][1]."\">".$links_descripcion[$i][1]."</A><BR>\n";
}
echo 
"<br>total links leidos: ".$i;

?>
En el ejemplo se leen 242 links extraidos entre HTML común ... lo procesó en: 0.0988030433655 segundos aprox. en mi PC "servidor" AMD K6-2 a 350MHz de la época xD...
(abriendo el fichero .. con mi kka de conexion modem 56K acceso comuntado corriente: 5.03578197956 segundos aprox.)

.. No es perfecta todavía la expresion regular .. habria q refinarla .. pero funciona bastan bien .. (por si acaso .. el código no es mio .. por lo menos las exp. regulares .. las saque de google .. aqui y allá xD).

---------------------

Sobre lo de comprobar si un URL es valido o no .. se hace via sockets conectando por HTTP directo .. y leyendo el error q devuelve (un 500 o un 404 por ejemplo algo distinto al 200 creo q es el q fué correcta la conexión) ..

Aquí tienes algunos:
http://www.hotscripts.com/PHP/Script...Link_Checking/
(para q te fijes en el código) ...

Un saludo,

Última edición por Cluster; 13/01/2003 a las 22:59
  #12 (permalink)  
Antiguo 14/01/2003, 19:34
 
Fecha de Ingreso: diciembre-2002
Mensajes: 23
Antigüedad: 21 años, 11 meses
Puntos: 0
Gracias Cluster! He aprendido mucho con este post q es de lo q se trata. Pero por ahora creo q me he qdado estancado en lo de los sockets. De todas formas voy a seguir investigando, aunq he empezado a programarlo en java también por la posibilidad de hacerlo en multihilo.

¿Php no maneja hilos verdad? Es q no encontré nada en la documentación.

Un saludo y gracias de nuevo cluster. Te mantendré informado de mis progresos.
  #13 (permalink)  
Antiguo 15/01/2003, 03:50
Avatar de dabogar  
Fecha de Ingreso: diciembre-2002
Ubicación: Valenciaaaa es la tierra de las flores ...
Mensajes: 33
Antigüedad: 21 años, 11 meses
Puntos: 0
De lo poco que puedo aportar ya que ustedes tienen mucho nivel por aquí, el protocolo HTTP maneja los siguientes códigos de información en la conexión.

o 2xx: Acción recibida correctamente

o 4xx: Error en el Cliente

o 5xx: Error en Servidor

Te contesto yo a los multihilos, por ejecutarse PHP desde un servidor creo que no tiene la posibilidad de crear hilos de ejecución, eso está reservado a los lenguajes de programación (Java lo hace de lujo por cierto).

Saludos
  #14 (permalink)  
Antiguo 15/01/2003, 07:28
 
Fecha de Ingreso: diciembre-2002
Mensajes: 23
Antigüedad: 21 años, 11 meses
Puntos: 0
Gracias Dabogar! Eso lo tenía claro, pero no he conseguido tratar bien los códigos 302 (redirecciones). El código q e hecho abre una conexión y lee el header, pero si este es un 302 lo sigue, y al final se convierte el 200.

En Java puedo hacer q no siga las redirecciones, pero en php no he encontrado nada parecido. Por cierto, q ya lo tengo bastante avanzado. Un saludo!
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 21:38.