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"]) . "&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"]))
.
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.
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ý.
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í.
Diskuse je zrušena z důvodu spamu.