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?

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.

Vložit komentář

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:

avatar © 2005-2018 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.