Vyjmutí parametru z URL

Školení, která pořádám

Čas od času, např. při přechodu na další stránku výsledků vyhledávání, je potřeba předat skoro všechny parametry stránky a změnit jen jeden (číslo stránky). Pokud je parametrů jen pár, dá se URL zkonstruovat jejich výčtem, při velkém množství je pohodlnější využít např. QUERY_STRING a číslo stránky jen změnit, přidat (při přechodu z první stránky) nebo vyjmout (při přechodu na první stránku). To je ošemetná operace, nahrazovaný parametr se může nacházet na různých místech a slušností je v URL nechat jen to, co je tam opravdu potřeba (tedy žádné přebytečné & nebo ?). Na jednom řádku tuto úlohu řeší následující funkce:

<?php
// zkonstruování URL výčtem parametrů
echo "search.php?search=" . urlencode($_GET["search"]) . "&amp;page=" . ($_GET["page"] + 1);

/** Vyjmutí parametru z URL
* @param string URL
* @param string regulární výraz parametru k vyjmutí
* @return string URL s vyjmutým parametrem
*/
function remove_from_url($url, $param) {
    return preg_replace("~(\\?)($param)=[^&]*&|[&?]($param)=[^&]*~", '\\1', $url);
}
echo htmlspecialchars(remove_from_url($_SERVER["REQUEST_URI"], "page"));
?>

V PHP 5 můžeme také použít funkci http_build_query, která z pole vygeneruje řetězec pro použití v URL. Pokud této funkci chceme předat všechny parametry kromě jednoho, můžeme použít array_diff_assoc($_GET, array("page" => $_GET["page"])).

Jakub Vrána, Řešení problému, 22.5.2006, diskuse: 8 (nové: 0)

Diskuse

gaspoda:

Vždycky když se bavím s někým o tvorbě webu tak mě jako první zajímá jak pracuje právě s tímto, jak spravuje přenos stavů mezi skripty. IMHO to je věc, na které se ukáže kvalita naprogramování frameworků.

Tak tedy, používáte na přenos stavů nějakou knihovnu?

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL: Reakce na: gaspoda

Lukas:

Relevantni otazka: vi nekdo, jak uvnitr skriptu ziskat adresu, pomoci ktere byl dokument zavolan? Cili to, co mel uzivatel v adresnim radku. (Neuvazuju ted mod_rewrite.) Delal jsem to tak, ze jsem si poskladal adresu z nekolika promennych v $_SERVER[]. Neni to ale zavisle na tom, jaky je pouzity server? Pochybuju, ze vsechny ruzne servery vyplni spravne vsechny hodnoty toho pole. Tim padem u skriptu pouzivajicich neco takoveho je nutne uvadet neco jako "vyzaduje Apache" (samozrejme, pripad teto funkce to nebude, pac tady je to jen jedna polozka a to se vsakne).

Hever:

No, asi nedám kompletně prověřenou odpověď, ale myslím, že PHP_SELF a QUERY_STRING v $_SERVER budou "všechny" servery podporovat. Mimo to se proměnné z url dají najít v $_GET.

ikona dgx:

http://www.dgx.cz/trine/item/php-soubor-cesta-a-url-prehledne

ikona dgx:

uff, tak to nevím jestli je dobrá cesta. Určitě bych nespoléhal na to, co mi kdo podstrčí do QUERY_STRING, ale raději vždy přímo tvořil vlastní řetězec, tedy z parametrů, které skutečně budu potřebovat.

Pro PHP4 se dá http_build_query nahradit asi takto

<?php
function dgx_buildGET($inputArr, &$outputStr, $prefix='', $postfix='')
{
    foreach ($inputArr as $key => $value)
        if (is_array($value))
            dgx_buildGET($inputArr[$key], $outputStr, $prefix . urlencode($key) . $postfix . '[', ']');
        else
            $outputStr .= '&' . $prefix . urlencode($key) . $postfix . '=' . urlencode((string) $value);
}

function
dgx_http_build_query($arr)
{
    $query = '';
    dgx_buildGET((array) $arr, $query);
    if (strlen($query)) $query[0] = '?';
    return $query;
}

$arr['param'] = 'value';
$arr['param2'] = 'value2';

// dgx_buildGET($arr, $query);
// nebo lepe:

$query = dgx_http_build_query($arr);
?>

Rozdíl je v tom, že vrátí i úvodní otazník, je-li tedy třeba (je-li v poli vůbec nějaký parametr). Takže můžeme výsledek hned přilepit za jméno souboru.

martinpav:

Je nejaký špeciálny dovod na predávanie &$outputStr v dgx_buildGET pomocou referencie? Viem že ušetríš pár bajtov v pamäti ale nezdá sa mi to byť dôvod prečo si to použil.
Kód ktorý mení hodnoty vstupných paramentrov sa mi zdá trošku neprehľadný.

ikona dgx:

Důvod je ten, že se $outputStr uvnitř funkce modifikuje. Samozřejmě to lze přepsat takto (a nejspíš to bude přehlednější):

<?php

function dgx_buildGET($inputArr, $prefix='', $postfix='')
{
    $s = '';
    foreach ((array) $inputArr as $key => $value)
        if (is_array($value))
            $s .= dgx_buildGET($inputArr[$key], $prefix . urlencode($key) . $postfix . '[', ']');
        else
            $s .= '&' . $prefix . urlencode($key) . $postfix . '=' . urlencode((string) $value);
    return $s;
}
?>

a pak volat

<?php

$query
= dgx_buildGET($arr);

// záměna prvního & na ?
if (strlen($query)) $query[0] = '?';
?>

p.s. referencí pameť neušetříš, naopak často vede k dramatickému zpomalení programu - tedy právě v situacích, kdy se jejím užitím snaží programátor situaci zrychlit. Reference není pointer. Je dobré vědět, že PHP proměnné (řetězce i složitá pole) předávané BEZ reference vůbec nekopíruje, pokud je funkce nepozmění.

martinpav:

To čo si napísal viem a prave preto som sa čudoval.
A taktiež viem co znamena "root of all evil" :).

Ohľadom referencii som čerpal z:
http://www.derickrethans.nl/files/phparch-…-article.pdf

PS: sry za OT.
avatar © 2005-2019 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.