Manipular una cadena de URL agregando parámetros GET

93

Quiero agregar parámetros GET a URL que pueden y no pueden contener parámetros GET sin repetir ?o &.

Ejemplo:

Si quiero agregar category=action

$url="http://www.acme.com";
 // will add ?category=action at the end

$url="http://www.acme.com/movies?sort=popular";
 // will add &category=action at the end

Si nota que estoy tratando de no repetir el signo de interrogación si lo encuentra.

La URL es solo una cadena.

¿Cuál es una forma confiable de agregar un parámetro GET específico?

Ryan
fuente
Sólo tiene que utilizar: echo http_build_url($url, array("query" => "the=query&parts=here"), HTTP_URL_JOIN_QUERY);. Pero necesitará pecl install pecl_httpo instalar jakeasmith / http_build_url a través del compositor.
Ema4rl

Respuestas:

188

Método básico

$query = parse_url($url, PHP_URL_QUERY);

// Returns a string if the URL has parameters or NULL if not
if ($query) {
    $url .= '&category=1';
} else {
    $url .= '?category=1';
}

Más avanzado

$url = 'http://example.com/search?keyword=test&category=1&tags[]=fun&tags[]=great';

$url_parts = parse_url($url);
// If URL doesn't have a query string.
if (isset($url_parts['query'])) { // Avoid 'Undefined index: query'
    parse_str($url_parts['query'], $params);
} else {
    $params = array();
}

$params['category'] = 2;     // Overwrite if exists
$params['tags'][] = 'cool';  // Allows multiple values

// Note that this will url_encode all values
$url_parts['query'] = http_build_query($params);

// If you have pecl_http
echo http_build_url($url_parts);

// If not
echo $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'] . '?' . $url_parts['query'];

Deberías poner esto en una función al menos, si no en una clase.

andrewtweber
fuente
2
Tampoco olvide agregar el valor de la categoría
Doug T.
4
@DougT. no todos los parámetros necesitan un valor. Por ejemplo, ?logoutse puede comprobar conisset($_GET["logout"])
rybo111
Este enfoque es bueno cuando sabe que el parámetro 'categoría' aún no está en la URL. Si el parámetro ya está en una URL, PHP debería tomar el valor de la última aparición del parámetro en la URL, por lo que la solución de @andrewtweber aún funciona. Sin embargo, me gusta más la siguiente solución stackoverflow.com/a/4101638/99256 .
Martin Vseticka
-1 por no reemplazar un parámetro si ya existe. No se menciona explícitamente en la pregunta, pero es lógica y semánticamente obligatoria.
Daniel W.
1
Sólo tiene que utilizar: echo http_build_url($url, array("query" => "the=query&parts=here"), HTTP_URL_JOIN_QUERY);. Pero necesitará pecl install pecl_httpo instalar jakeasmith / http_build_url a través del compositor.
Ema4rl
55

Aquí hay una versión más corta de la respuesta aceptada:

$url .= (parse_url($url, PHP_URL_QUERY) ? '&' : '?') . 'category=action';

Editar: como se discutió en la respuesta aceptada, esto es defectuoso porque no verifica si categoryya existe. Una mejor solución sería tratar el $_GETpor lo que es, una matriz, y usar funciones como in_array().

rybo111
fuente
Tenga en cuenta que esto solo funcionará con un único parámetro agregado; de lo contrario, agregará un? si no hubo consulta original.
Mgamerz
@Mgamerz a menos que no te entienda bien, eso es lo que pidió el OP. Funciona varias veces, debido a que .antes de =.
rybo111
Pero, ¿la consulta no existirá si agrega un parámetro a la URL (por lo tanto, agrega un?), Y si lo hace nuevamente, agregará otro? (A menos que se suponga que debe ejecutar la primera línea nuevamente)? ¿Cómo se actualiza $ query?
Mgamerz
@Mgamerz Veo lo que quieres decir ahora. Sí, debería repetir la primera línea cada vez para comprobar si $urlya tiene parámetros. Editado.
rybo111
1
No maneja URL con #.
NateS
19
$data = array('foo'=>'bar',
              'baz'=>'boom',
              'cow'=>'milk',
              'php'=>'hypertext processor');

$queryString =  http_build_query($data);
//$queryString = foo=bar&baz=boom&cow=milk&php=hypertext+processor

echo 'http://domain.com?'.$queryString;
//output: http://domain.com?foo=bar&baz=boom&cow=milk&php=hypertext+processor
Tom Claus
fuente
Sólo tiene que utilizar: echo http_build_url($url, array("query" => "the=query&parts=here"), HTTP_URL_JOIN_QUERY);. Pero necesitará pecl install pecl_httpo instalar jakeasmith / http_build_url a través del compositor.
Ema4rl
8

Utilice strpos para detectar un?. Ya que ? solo puede aparecer en la URL al comienzo de una cadena de consulta, usted sabe si ya existen parámetros de get y necesita agregar parámetros usando &

function addGetParamToUrl(&$url, $varName, $value)
{
    // is there already an ?
    if (strpos($url, "?"))
    {
        $url .= "&" . $varName . "=" . $value; 
    }
    else
    {
        $url .= "?" . $varName . "=" . $value;
    }
}
Doug T.
fuente
Enfoque bueno y fácil si le preocupa el rendimiento, ya que será mucho más rápido que parse_url y también menos intensivo en CPU. La compensación es que no está comprobando un $ varName existente.
Dennis Stücken
8

Esta función sobrescribe un argumento existente

function addToURL( $key, $value, $url) {
    $info = parse_url( $url );
    parse_str( $info['query'], $query );
    return $info['scheme'] . '://' . $info['host'] . $info['path'] . '?' . http_build_query( $query ? array_merge( $query, array($key => $value ) ) : array( $key => $value ) );
}
usuario2171027
fuente
¿Qué pasa si no hay ningún $info['query']conjunto? No lo has tenido en cuenta.
Darren
Si no se establece, $ info ['consulta'] se convierte en NULL y $ query se convierte en una matriz vacía. Entonces no es un problema.
Ajay Singh
7

Ejemplo con actualización de parámetros existentes.

También se utilizó url_encode y la posibilidad de no especificar el valor del parámetro

    <?
    /**
     * Add parameter to URL
     * @param string $url
     * @param string $key
     * @param string $value
     * @return string result URL
     */
    function addToUrl($url, $key, $value = null) {
        $query = parse_url($url, PHP_URL_QUERY);
        if ($query) {
            parse_str($query, $queryParams);
            $queryParams[$key] = $value;
            $url = str_replace("?$query", '?' . http_build_query($queryParams), $url);
        } else {
            $url .= '?' . urlencode($key) . '=' . urlencode($value);
        }
        return $url;
    }
Артур Курицын
fuente
5
<?php
$url1 = '/test?a=4&b=3';
$url2 = 'www.baidu.com/test?a=4&b=3&try_count=1';
$url3 = 'http://www.baidu.com/test?a=4&b=3&try_count=2';
$url4 = '/test';
function add_or_update_params($url,$key,$value){
    $a = parse_url($url);
    $query = $a['query'] ? $a['query'] : '';
    parse_str($query,$params);
    $params[$key] = $value;
    $query = http_build_query($params);
    $result = '';
    if($a['scheme']){
        $result .= $a['scheme'] . ':';
    }
    if($a['host']){
        $result .= '//' . $a['host'];
    }
    if($a['path']){
        $result .=  $a['path'];
    }
    if($query){
        $result .=  '?' . $query;
    }
    return $result;
}
echo add_or_update_params($url1,'try_count',1);
echo "\n";
echo add_or_update_params($url2,'try_count',2);
echo "\n";
echo add_or_update_params($url3,'try_count',3);
echo "\n";
echo add_or_update_params($url4,'try_count',4);
echo "\n";
shengbin_xu
fuente
3
gran trabajo, solo reemplace la línea $query = $a['query'] ? $a['query'] : '';por$query = isset($a['query']) ? $a['query'] : '';
emmgfx
4
 /**
 * @example addParamToUrl('/path/to/?find=1', array('find' => array('search', 2), 'FILTER' => 'STATUS'))
 * @example addParamToUrl('//example.com/path/to/?find=1', array('find' => array('search', 2), 'FILTER' => 'STATUS'))
 * @example addParamToUrl('https://example.com/path/to/?find=1&FILTER=Y', array('find' => array('search', 2), 'FILTER' => 'STATUS'))
 *
 * @param       $url string url
 * @param array $addParams
 *
 * @return string
 */
function addParamToUrl($url, array $addParams) {
  if (!is_array($addParams)) {
    return $url;
  }

  $info = parse_url($url);

  $query = array();

  if ($info['query']) {
    parse_str($info['query'], $query);
  }

  if (!is_array($query)) {
    $query = array();
  }

  $params = array_merge($query, $addParams);

  $result = '';

  if ($info['scheme']) {
    $result .= $info['scheme'] . ':';
  }

  if ($info['host']) {
    $result .= '//' . $info['host'];
  }

  if ($info['path']) {
    $result .= $info['path'];
  }

  if ($params) {
    $result .= '?' . http_build_query($params);
  }

  return $result;
}
Londeren
fuente
3
$parameters = array();

foreach ($get as $key => $value)
{
     $parameters[] = $key.'='.$value;
}

$url = 'http://example.com/movies?'.implode('&', $parameters);
TaylorOtwell
fuente
3

Creo que deberías hacer algo como esto.

class myURL {
    protected $baseURL, $requestParameters;

    public function __construct ($newURL) {
        $this->baseurl = $newURL;
        $this->requestParameters = array();
    }

    public function addParameter ($parameter) {
        $this->requestParameters[] = $parameter;
    }

    public function __toString () {
        return $this->baseurl.
               ( count($this->requestParameters) ?
                 '?'.implode('&', $this->requestParameters) :
                 ''
                 );
    }
}

$url1 = new myURL ('http://www.acme.com');
$url2 = new myURL ('http://www.acme.com');
$url2->addParameter('sort=popular');
$url2->addParameter('category=action');
$url1->addParameter('category=action');

echo $url1."\n".$url2;
Hammerita
fuente
1

Después de buscar muchos recursos / respuestas sobre este tema, decidí codificar el mío. Según la respuesta de @ TaylorOtwell aquí, así es como proceso la solicitud $ _GET entrante y modifico / manipulo cada elemento.

Suponiendo que la URL es: http://domain.com/category/page.php?a=b&x=y Y solo quiero un parámetro para ordenar: ¿? Desc = column_name o? Asc = column_name. De esta manera, un solo parámetro de URL es suficiente para ordenar y ordenar simultáneamente. Entonces, la URL será http://domain.com/category/page.php?a=b&x=y&desc=column_name en el primer clic de la fila de encabezado de la tabla asociada.

Luego tengo encabezados de filas de tabla que quiero ordenar DESC en mi primer clic y ASC en el segundo clic del mismo encabezado. (Cada primer clic debe "ORDER BY COLUMNA DESC" primero) Y si no hay clasificación, se ordenará por "fecha y luego id" de forma predeterminada.

Puede mejorarlo aún más, como si pudiera agregar funciones de limpieza / filtrado a cada componente $ _GET, pero la estructura siguiente sienta las bases.

foreach ($_GET AS $KEY => $VALUE){
    if ($KEY == 'desc'){
        $SORT = $VALUE;
        $ORDER = "ORDER BY $VALUE DESC";
        $URL_ORDER = $URL_ORDER . "&asc=$VALUE";
    } elseif ($KEY == 'asc'){
        $SORT = $VALUE;
        $ORDER = "ORDER BY $VALUE ASC";
        $URL_ORDER = $URL_ORDER . "&desc=$VALUE";
    } else {
        $URL_ORDER .= "&$KEY=$VALUE";
        $URL .= "&$KEY=$VALUE";
    }
}
if (!$ORDER){$ORDER = 'ORDER BY date DESC, id DESC';}
if ($URL_ORDER){$URL_ORDER = $_SERVER[SCRIPT_URL] . '?' . trim($URL_ORDER, '&');}
if ($URL){$URL = $_SERVER[SCRIPT_URL] . '?' . trim($URL, '&');}

(Puede usar $ _SERVER [SCRIPT_URI] para la URL completa que comienza con http://domain.com )

Luego utilizo el $ ORDER resultante que obtengo arriba, en la consulta MySQL:

"SELECT * FROM table WHERE limiter = 'any' $ORDER";

Ahora la función para mirar la URL si hay una clasificación previa y agregar el parámetro de clasificación (y ordenación) a la URL con "?" o "&" según la secuencia:

        function sort_order ($_SORT){
            global $SORT, $URL_ORDER, $URL;
            if ($SORT == $_SORT){
                return $URL_ORDER;
            } else {
                if (strpos($URL, '?') !== false){
                    return "$URL&desc=$_SORT";
                } else {                        
                    return "$URL?desc=$_SORT";
                }
            }
        }

Finalmente, el encabezado de la fila de la tabla para usar la función:

        echo "<th><a href='".sort_order('id')."'>ID</a></th>";

Resumen: esto leerá la URL, modificará cada uno de los componentes $ _GET y creará la URL final con los parámetros de su elección con la forma correcta de uso de "?" y "&"

Tarik
fuente
0
 public function addGetParamToUrl($url, $params)
{
    foreach ($params as $param) {
         if (strpos($url, "?"))
        {
            $url .= "&" .http_build_query($param); 
        }
        else
        {
            $url .= "?" .http_build_query($param); 
        }
    }
    return $url;
}
Maor Kavod
fuente
0

otra versión de función mejorada. Mezcla de respuestas existentes con pequeñas mejoras (compatibilidad con puertos) y correcciones de errores (comprobando las claves correctamente).

/**
 * @param string $url original url to modify - can be relative, partial etc
 * @param array $paramsOverride associative array, can be empty
 * @return string modified url
 */
protected function overrideUrlQueryParams($url, $paramsOverride){
    if (!is_array($paramsOverride)){
        return $url;
    }

    $url_parts = parse_url($url);

    if (isset($url_parts['query'])) {
        parse_str($url_parts['query'], $params);
    } else {
        $params = [];
    }

    $params = array_merge($params, $paramsOverride);

    $res = '';

    if(isset($url_parts['scheme'])) {
        $res .= $url_parts['scheme'] . ':';
    }

    if(isset($url_parts['host'])) {
        $res .= '//' . $url_parts['host'];
    }

    if(isset($url_parts['port'])) {
        $res .= ':' . $url_parts['port'];
    }

    if (isset($url_parts['path'])) {
        $res .= $url_parts['path'];
    }

    if (count($params) > 0) {
        $res .= '?' . http_build_query($params);
    }

    return $res;
}
Roman86
fuente
0

Pruebe esta función para agregar parámetros de URL .

Luego, puede deshabilitar el enlace cuando el parámetro está configurado para que no haya un parámetro de URL duplicado.

<?php
  function addQueryString($a)
                {
             if (empty($_SERVER['QUERY_STRING']))
               return '?' . $a;
             else if (!empty($_SERVER['QUERY_STRING']))
              return '?' . $_SERVER['QUERY_STRING'] . '&' . $a;
                }
?>

 <a href="<?php echo addQueryString('lang=en'); ?>">test</a>
 <a href="<?php echo addQueryString('category=5'); ?>">sat</a>
csandreas1
fuente