[PHP]Nao gosto da minha função recursiva

Armadillo

Folding Member
Já me mandou o serviço do apache abaixo umas nao-sei-quantas vezes e é lento que nem um caracol!
Sugestoes para melhorar o meu script serao muito bem aceites!
O que o meu codigo faz é devolver num vector unidimensional (requisito imprescindivel) todas as pastas existentes, dado um caminho inicial.

PHP:
<?php


//exemplo de utilizacao da funcao
//Para devolver todos os ficheiros e directorios num vector, dado um caminho
// $filestructure = pesquisa_dir_recursivamente('caminho/a/pesquisar');
 
//Para devolver todos os ficheiros  e directorios num vector, dado um caminho e uma extensao de ficheiro
// $filestructure = pesquisa_dir_recursivamente('caminho/a/pesquisar', 'extensao'); 

 function pesquisa_dir_recursivamente($directorio, $filtro=FALSE)
 {

if(substr($directorio,-1) == '/')                                                //se o caminho tiver no fim uma barra
    {
        $directorio = substr($directorio,0,-1);                                    // removemos.
    }

    
if(!file_exists($directorio) || !is_dir($directorio))                            //se caminho for invalido  ou nao for um directorio...
    {
    return FALSE;                                                                // ... retorna FALSE e sai da funcao
}elseif(is_readable($directorio))                                                // ... se o caminho eh valido
    {
     $directorio_list = opendir($directorio);                                    // abrimos o directorio
     while (FALSE !== ($ficheiro = readdir($directorio_list)))                    // e procuramos items nele
     {
        if($ficheiro != '.' && $ficheiro != '..')                                //se apontador de ficheiro nao for o actual directorio ou o directorio pai
        {
            $path = $directorio.'/'.$ficheiro;                                    //construimos o novo caminho a pesquisar
            if(is_readable($path))                                                // se o caminho for valido
        {
                $subdirs = explode('/',$path);                                     // dividimos o novo caminho em directorios 
                if(is_dir($path))                                                // se o novo caminho for um directorio
                     {
                     $directorio_tree[] = array($path,
                    pesquisa_dir_recursivamente($path, $filtro));                // pesquisamos o novo caminho chamando esta funcao (recursividade)
                    
                }
            }
           }
     }

    closedir($directorio_list);                                                 // fechar directorio
    return $directorio_tree;                                                    // retornar a lista de ficheiros
    }
else
    {                                                                            // se o caminho nao for valido
     return FALSE;                                                                // ... retorna FALSE
    }
}
    

//testando funcoes

function listaArray(&$item2, $key)
{

    global $pastas;
    //echo "$item2<br>\n";
    
    if (!is_array($item2) && !is_null($item2))        //se nao for um vector
        {
        $pastas[]=$item2;                            //adiciona item ao vector 
        }
    array_walk($item2, 'listaArray');
}


$array = pesquisa_dir_recursivamente('..\..');     //ler disco em busca de dirs
array_walk($array, 'listaArray');                //retornar apenas as dirs

$pastas=array_unique($pastas);                    //remover possiveis duplicacoes nas pastas(caso dos null)
sort($pastas);
echo '<pre>';
var_dump ($pastas);
echo '</pre>';
Também nao consigo fazer uma pesquisa por um caminho do tipo "c:\programas", apenas "..\..\".
Acho que o codigo esta bem comentado. Se tiverem duvidas em relação a alguma coisa, buzinem
Ja agora, estou a usar a versao 4.4.3 do PHP.
:msmiley1:
 
Última edição pelo moderador:
funcões recursivas em web scripting

não sei o estas a fazer concretamente, mas não é aconselhavel faze-lo (recursivamente ou não) nesse modelo especifico.

existem muitas "variaveis" não deterministicas neste problema/plataforma que inviabilizam uma solução recursiva optima e funcional...


Alternativas:

1. Lês um nivel apenas e permites ao utilizador inter-agir , lendo 1 nivel de cada vez quando se selecciona uma pasta. podes/deves usar ajax para isso. (+- como as tree views)

2. Fazes um webservice que implemente a tua função recursiva, e chama-lo asyncronamente do php. (já não mexo em php à algum tempo mas penso já ser possivel faze-lo em php)

3. Fazes uma função/webservice que te retorna o nivel que desejas apenas, e implementas a lógica/recursividade usando ajax (javascript) :)


ainda assim optava pela solução 1 ou 3.

/ing
 
Pois é, so que isto é para ser implementado num sistema passivo, ou seja, nao vai haver interacção com o utilizador.
Em relação aos niveis, torna-se-me impossivel de saber quantos niveis é que terei que ler, visto que este script vai correr de forma autónoma, num servidor ao qual nao tenho acesso directo e o meu script tem que ser suficientemente polivalente para procurar um determinado ficheiro numa localização qualquer.
Em relação ao ajax, penso que só é possivel utiliza-lo com um webbrowser (não tenho a certeza), coisa que nao vai acontecer no meu caso (executo os php atraves do wget despolotado através do cron) e tambem porque, na minha opiniao, nao se coaduna com o espirito do meu projecto (carago, isto ficou caro em palavras! ;)).

Sei que sao muitas limitações que imponho mas tem que ser executado desta forma.
Ainda assim, agradeço a vossa ajuda.

Obrigado.
 
cron

se o vais chamar do cron, pq usas Php?

pq não fazes um script em perl/java etc que faça isso e retorne o respectivo XML ?

neste caso/modelo já te aconselharia o uso de recursividade .

/ing
 
1. nao fui eu que decidi, ja estava implementado parte do sistema em php e para a integração/interacção entre os varios modulos ser mais rapida optou-se por continuar a usar php.

2. nao sei se o nosso servidor corre java ou perl (riam-se de mim!, eu sou amigo do bill, que é que se há-de fazer?).
Tem uma distro de linux altamente modificada e nao convem instalarmos mais nada a nao ser com o que ja vem de origem (questao de compatibilidade com futuras actualizações do fabricante da maquina/os). Apenas sei que aquela coisa corre php 4.4.3.
Tenho acesso ao servidor muito limitado, nao posso andar a inventar pq senao tadinho do programador... Tou tipo do Liedson, parece um quartel general ;)
 
:),

posso ainda sugerir o uso de bash.

echo "<pre>" >out.txt
find /home -name '*' >> out.txt
echo "</pre>" >>out.txt



sempre resulta , depois só tens que tratar a listagem :)

/ing
 
vais-me desculpar, mas executo isso no php? como se fosse na command line (sei que é possivel, nao me lembro é da sintax)?

edit:
ou seja:
PHP:
$resultCommandLine=executacommandline( find /home -name '*');
$tmp = explode(char(13), $resultCommandLine);
//... etc bla-bla-bla
humm?
 
Última edição pelo moderador:
nao sei se o nosso servidor corre java ou perl
epa.. um servidor *NIX sem Perl é como um jardim sem flores! :-)

Vejo aqui uma excelente oportunidade para te debruçares sobre o Perl ;-) isso que pretendes fazes em 6 (vá lá... 7) linhas de código.
 
vais-me desculpar, mas executo isso no php?? como se fosse na command line (sei que é possivel, nao me lembro é da sintax)?

Se quiseres podes chamar atraves do php, mas tava a pensar no seguinte:

fazes um ficheiro bash(usa o chmod para tornar o ficheiro executavel) em linux .
depois chama-lo a partir do cron, e este gera um ficheiro ou.txt
depois podes ler esse fich do php.


se o ficheiro se chamar script.bash , chama-lo da seguinte forma: ./script.bash /home

referencias bash http://www.linux.org/docs/ldp/howto/Bash-Prog-Intro-HOWTO.html#toc5
referencias do find http://www.linuxdevcenter.com/linux/cmd/cmd.csp?path=f/find


#!/bin/bash
echo "<pre>" >out.txt
find $1 -name '*' >> out.txt
echo "</pre>" >>out.txt


/ing
 
Como ja disse:

Tenho acesso ao servidor muito limitado, nao posso andar a inventar pq senao tadinho do programador... Tou tipo do Liedson, parece um quartel general ;)

:iconlock:riam-se riam-se, oxalá nuca vos aconteça a vós, nem consigo imprimir um naco de codigo!:005:

vamos la malta, tem que ser em php, nada de brainfuck ou perl.:lol:
nao me abandonem...

Se quiseres podes chamar atraves do php, mas tava a pensar no seguinte:

fazes um ficheiro bash(usa o chmod para tornar o ficheiro executavel) em linux .
depois chama-lo a partir do cron, e este gera um ficheiro ou.txt
depois podes ler esse fich do php.


se o ficheiro se chamar script.bash , chama-lo da seguinte forma: ./script.bash /home

referencias bash http://www.linux.org/docs/ldp/howto/Bash-Prog-Intro-HOWTO.html#toc5
referencias do find http://www.linuxdevcenter.com/linux/cmd/cmd.csp?path=f/find


#!/bin/bash
echo "<pre>" >out.txt
find $1 -name '*' >> out.txt
echo "</pre>" >>out.txt


/ing

eh pá, isso parece muita volta so pra fazer um list aos dirs existentes num outro dir.
e depois, nao me parece muito pratico ter um bash a ser chamado pelo cron, que irá gerar um ficheiro, e depois despolotar o script principal (e se o 2º começa antes do 1º acabar, sabe-se lá, os servidares as vezes ficam tolos!).

Alguem se lembra do comando para executar um comando na shell atraves do php?
Acham esta a solução mais limpinha e simples de fazer o que eu quero em PHP?

Obrigado a todos.
 
Última edição pelo moderador:
basicamente tenho que pesquisar uns ficheiros (nao sei quais, por isso pode ir por parametro a extensao ou localizo-os posteriormente sabendo em que directórios tenho que pesquisar) que estao localizados sabe-se lá onde e importar o conteudo desses ficheiros para a bd em mysql.
Posso ter que lidar com uns valentes milhares ou centenas de milhares desses ficheiros e por uma arvore de directorios manhosa.

PS:Slack_guy, tu deves pensar que eu tenho ideias malucas (já me ajudaste em algumas), mas nao sou eu, ve na minha assinatura o link 'isto é a minha vida...'. É a pura verdade

Obrigado

 
Última edição:
Onde é que eu já vi isto...

Todas a soluções de listar ficheiros numa pasta e sub-pastas que vi até agora recorriam a recursividade...
Poderás é tentar separar as coisas para não sobrecarregar o sistema.

Função 1 - obter o caminho de todas as pastas e subpastas > $caminhos = array()
Função 2- For each $caminhos as $caminho > $ficheiros = array()
...

EDITADO: ou então visitas este sitezeco.
 
Última edição:
basicamente tenho que pesquisar uns ficheiros
isso quer dizer que tens de abrir, ler e procurar por determinado padrão dentro dos ficheiros? ou é pelos nomes dos ficheiros?

Será tipo isto?
Dada a pasta /home/slack como ponto de partida, percorre todos os ficheiros e pastas e devolve o conteúdo de todos os ficheiros com extensão 'txt' ou 'dat' que contenham a expressão 'EXPRESSAO'.

Se é isto, a única coisa que me falta saber é... em que formato queres o output? Aqui tens duas opções:
1) são devolvidos os nomes (e respectivos caminhos) dos ficheiros;
2) é criado um ficheiro com determinadas marcas (XML?) com todos os conteúdos dos ficheiros encontrados. É devolvido o nome e o caminho deste ficheiro. O teu programa encarrega-se de fazer o parse do ficheiro.
 
EDITADO: ou então visitas este sitezeco.

Nao posso usar scandir porque estou a usar a versao 4.4.3 do PHP.



Slack_guy, apenas preciso da localização dos ficheiros definidos por uma prefixo no nome do ficheiro (ex: c:\data\export\2001\12\FACT_xxxx_xxxxxx.YYY | c:\data\export\2002\1\1233\AST_xxxxxx.YYY). Para processar o conteudo dos ficheiros, nao preciso de nada, pois ja esta feito há uns aninhos.

Em relação ao output preciso de um vector unidimensional com o nome e caminho dos ficheiros.

Para simplificar, e ja tendo uma função que pesquisa os ficheiros dado um determinado prefixo e num determindado directorio, neste momento apenas preciso dos directorios existentes num determinado caminho de origem num vector unidimensional.

Espero ter sido claro e explicito,
Obrigado pessoal pela ajuda.
 
Última edição:
Boas eu não sei nada de PHP....apenas tou a ver o algoritimo com base no que sei de C, mas esta parte aqui


Código:
$subdirs = explode('/',$path);        // dividimos o novo caminho em directorios 
if(is_dir($path))                          // se o novo caminho for um directorio
{
  $directorio_tree[] = array($path,
  pesquisa_dir_recursivamente($path, $filtro));               
}

nao percebo o que faz o explode, mas não é $subdirs que fica com a path do novo directorio?
 
o que o explode faz é dividir uma string num array de strings, sendo dado um caracter "divisor"
Acho que essa linha se pode ignorar. (vou comentar essa linha)

É assim, a função funciona lindamente, excepto com com caminhos do tipo /opt/site/_Site1 ou c:\programas\site\_Site1\
, ate agora só consegui por isto a funcionar com caminhos do tipo .. e ../..

Gracias
 
$directorio_tree[] = array($path, pesquisa_dir_recursivamente($path, $filtro));

o que acontece quanto é returnado o valor FALSE na funcao? E se a mesma e returnar um array de chars?
 
Back
Topo