8791 sujets

Développement web côté serveur, CMS

Hola! Smiley biggrin

Ça fait un moment que j'utilise cette fonction, je l'utilise même tout le temps, ça sert a rajouter des paramètres à une url, si l'url les a déjà, ça les remplaces par les nouveaux:

echo url_param('/do_something.php?var1=1&var2=1','var1=2&var2=2&var3=2')
///do_something.php?var1=2&var2=2&var3=2


C'est vraiment très pratique, c'est pour ça que je l’utilise dans tout les projet, et que, petit à petit, elle s'affine, voilà la dernière version:


url_param($url,$param)
{
    $param = str_replace( '&', '&',$param);
    $status  = preg_match('~^([^?#]*)(\?([^#]*))?(#(.*))?~',$url,$matches);
    $url = (isset($matches[1]))? $matches[1] : '';
    if(isset($matches[3])){
        parse_str($matches[3],$vars);
        $url = $url.'?';
        foreach($vars as $var=>$value){
            if(is_array($value)){
                foreach($value as $i=>$v){
                    if(!preg_match('~(^'.$var.'\[\]|&'.$var.'\[\])='.$v.'~',$param)) $url .= $var.'[]='.$v.'&';
                }   
            }else{
                if(!preg_match('~(^'.$var.'|&'.$var.')=~',$param)) $url .= $var.'='.$value.'&';
            }
        }
        $url .= $param;
    }else{
        $url = $url.'?'.$param;
    }
    if(isset($matches[4])) $url .= $matches[4];

    return $url;
}


Je me disais qu'elle pouvait peut être servir à d'autre et que vous auriez surement des commentaires éclairés pour encore l'améliorer Smiley biggrin
Modifié par matmat (11 May 2010 - 03:20)
Bonjour,

Je n'ai pas détaillé ta fonction, mais je pense que tu pourrais peut être utiliser preg_replace_callback() , explode() ou split()
et regarder vers les fonctions natives parse_url(), http_ build_ query()

Tous cela est bien entendu juste un avis.

Smiley cligne
Hello, happy birthday.

J'aurai eu la même approche que le commentaire précédent, à savoir, faire deux tableaux associatifs avec parse_url que j'aurai fusionné avec array_merge.

Honnêtement je ne voix pas l'utilité concrète d'une telle fonction.
Il existe déjà plusieurs fonctions pour faire ce que tu souhaites.
Voici un exemple de fonction écrite rapidement :


/**
 * @param string $url 
 * @param array $params Tableau indexé ou associatif de paramettres
 * @return string
 */
function url_param($url, $params) 
{ 
    $url = parse_url($url);
    // Analyse de la requête HTTP (string to array)
    parse_str($url['query'], $array_query);
    // merge des paramêtres
    $array_query = array_merge($array_query, $params); // Si les tableaux ont des clés en commun, la dernière valeur rencontrée écrasera l'ancienne 
    // Construction de la requête
    $query = http_build_query($array_query);
    // Reconstruction de l'url
    return $url['scheme'] .'://'. $url['user'] .':'. $url['pass'] .'@'. $url['host'] . $url['path'] .'?'. $query .'#'. $url['fragment']; 
}

Où $params est un tableau associatif ou indexé et $url une chaine de la forme '/do_something.php?var1=1&var2=1'
A toi de modifier cette fonction pour qu'elle prenne les paramètres du type que tu souhaites.

Je te laisse te diriger vers la doc php pour comprendre ce que fait chaque fonction. Smiley cligne
Modifié par moust (11 May 2010 - 20:08)
Merci bien!

Super réponses, para contre je vais en rester a ma regex, parce que parse_url() n'accepte pas les url relatives.

C'est un bonne idée de passer en array en paramètre, par contre j'ai aussi besoin de pouvoir passer une chaîne, j'ai écris ça pour le moment, c'est déjà mieux que l'original:


/** 
 * @param string $url  
 * @param array $params Tableau indexé ou associatif de paramettres ou chaine
 * @return string 
 */ 
function url_param($url, $params)  
{  
    $status  = preg_match('~^([^?#]*)(\?([^#]*))?(#(.*))?~',$url,$matches);
    $url = (isset($matches[1]))? $matches[1] : '';
      
    if(!is_array($params)){
        parse_str($params, $array_params); 
    }else{
        $array_params = $params;
    }
    
    if(isset($matches[3])){
        parse_str($matches[3], $array_query);
        $array_query = array_merge($array_query, $array_params);
    }else{
        $array_query = $array_params;
    }

    $query = http_build_query($array_query);
    $url = $url . '?' . $query;
    
    if(isset($matches[4])) $url .= $matches[4];
    
    return $url;  
} 
J'aurai tendance à dire que c'est inutile.

En théorie il ne faudrait pas le faire parce que ?var=1&var=2 est valide, et que certains programmes repèrent que "var" est mentionné deux fois et que ça a du sens pour eux (d'ailleurs PHP le fait aussi quand la variable se termine par "[]"). Bref, si tu ne t'adresses pas à une application interne, ce genre de simplifications est une erreur.

En pratique même si tu t'adresses à toi même vers une appli en PHP, il te suffit d'accoler les deux parties. ?var=1&var=2 est bien compris par PHP, il prendra la dernière valeur. Du coup lancer des regexp fréquemment juste pour ça m'apparait un peu dommage.

N'oubliez pas que PHP commence à avoir un certain age concernant les applis web. Si vous faites quelque chose qui vous parait standard, qui n'est pas spécifique à votre métier et votre applications, et que vous faites des regexp, c'est probablement que vous faites erreur (pas tout le temps, mais souvent) ou qu'il existe des fonctions pour ça.
Edas a écrit :
J'aurai tendance à dire que c'est inutile.
N'oubliez pas que PHP commence à avoir un certain age concernant les applis web. Si vous faites quelque chose qui vous parait standard, qui n'est pas spécifique à votre métier et votre applications, et que vous faites des regexp, c'est probablement que vous faites erreur (pas tout le temps, mais souvent) ou qu'il existe des fonctions pour ça.


Tout à fait d'accord avec cette idée, j'essaye également d'utiliser au maximun les fonctions natives, et de limiter les "fonctions utiles".

C'est vrai que jusque là je n'ai pas expliqué le pourquoi de la fonction. Des exemples donc:

Mon application a un système de cache avec un petit bouton qui permet de recharger la page, je fait donc:
Util::urlParam($GLOBALS['url']['request'],'cache=clear')


si je rajoute le paramètre comme tu le recommandes j'aurais mapage/?cache=clear&cache=clear&cache=clear&cache=clear et ce autant de fois que l’utilisateur recharge la page!

Dans une partie de l'application, j'ai un explorer de fichier qui permet de parcourir les fichiers télèchargé, pour cela j'envoie le nom du dossier dans l'url:
Util::urlParam($url['host'].$form['action'],'explorer='.$dir['path_var'])


La même chose, si l'utilisateur parcourt 100 dossiers j’aurais 100 fois la variable explorer.

Quelque fois j'utilise un calendrier, dans lequel on navigue par mois et année:
Util::urlParam($calendar['url'],'year='.$calendar['year_after'].'&month='.$calendar['month_after'])


Encore une fois le même problème, si utilisateur navigue dans la calendrier il va se retrouver avec une url immense.

La pagination et un autre exemple
Util::urlParam($url,'step='.$increase)


J'utilise cette fonction fréquemment si ce n'est tout le temps, car justement je me suis trop souvent prit la tête avec les & ou ? a la fin des urls et les répétition de variables sans fin.

Donc non, il ne suffit pas d'accoler les deux parties pour rajouter des paramètres, ou plutôt pas dans tout les cas. Bien sûr étant conscient que ma fonction utilise certaines ressources je ne l'utilise pas si l'ajout de paramètres et simple.

Le cas ou la variable utilise [] pour envoyer un tableau, était prit en compte dans la fonction initiale au début du sujet, finalement, comme je n'ai jamais envoyé un tableau par GET depuis que je programme, je me suis dit que c'était inutile de prendre en compte cette possibilité. Bien sûr, si la fonction est utilisé dans une autre application qui envoi des tableaux par GET, il faudra faire les modifications nécessaire.
Modifié par matmat (28 May 2010 - 16:27)