Autor Zpráva
Jcas
Profil
Doufám, že se na mě nebude nikdo zlobit, když si založím tyto poznámky. Samozřejmě se jedná o chyby, které vznikly nedostatečným, nebo nepozorným čtením manuálu, či návodu (opomenutí či vynechání jedné důležité věty). Nicméně jsem je udělal a tak je možné, že je udělá i někdo jiný. Třeba mu to poslouží. A třeba to poslouží jako zpětná vazba tvůrcům návodů.

Špatně zpracované data z formuláře.

- chyba může vzniknout díky existenci-neexistenci $_POST
<form method="post">
<select name="test">
<option>jedna</option>
<option>dva</option>
<option>jiná</option>
</select>
<input type="submit" value="odeslat" name="enter">
</form>
Pokud tento formulář odešleme, tak $_POST['test'] bude mít vždy nějakou hodnotu.
Výchozí hodnota je první volba.
isset($_POST['test']);   // true
empty($_POST['test']);   //false

// zpracování
// kontroluje jak odeslání, tak i jestli byla vybrána hodnota 'jiná'
if($_POST['test'] != 'jiná') {....}
else {.....}

Pokud ovšem obalíme <option> do <optgroup>, Tak tato kontrola je nedostatečná.
Při <optgroup> není vybrána výchozí položka. A pokud nevybereme - hodnota se neodešle.


Nyní jsou tedy možné 3 možnosti.
- uživatel nevybere nic a odešle form
- uživatel vybere 'jiná'
- uživatel vybere jinou položku, než je 'jiná'


<form method="post">
<select name="test" size="5">
<optgroup>
<option>jedna</option>
<option>dva</option>
</optgroup>
</select>
<input type="submit" value="odeslat">

// pokud nevybere nic
isset($_POST['test']);   // false
empty($_POST['test']);   //true

// toto zpracování neodhalí situaci, kdy uživatel nic nevybral a odeslal formulář.
if($_POST['test'] != 'jiná') {....}  // zde bude i situace, kdy nevybral nic.
else {.....}





var_dump() - vypsání proměnné

Potřeba pozorně číst návody. Je pravda, že u var_dump jsem učebnici php nečetl a četl jsem se svou lámavou angličtinou pouze manuál. O hodnotě NULL jsem tam nic nepřečetl. (nebo přešel, nebo přehlédl)

Výše zmíněný problém jsem nemohl odhalit, protože jsem si vypsal:
var_dump($_POST['test']); // vrátilo NULL a já žil v přesvědčení, že $_POST['test'] == null;

Takže pozor. Pokud není inicializovaná proměnná, tak var_dump vrací NULL!!!
Ovšem totéž platí, pokud nepřiřadíme aspoň něco.
$x;
var_dump($x);   // NULL 
jenikkozak
Profil
Jcas:
Pokud ovšem obalíme <option> do <optgroup>
Problém není způsobený použitím značkou <optgroup>, ale atributem size prvku <select> ve druhém uvedeném příkladu. Dá se vyřešit použitím atributu selected u výchozí položky.
PHP je v tomto nevinně. Záleží na prohlížeči, které položky odešle.
Jcas
Profil
jenikkozak:
Lze se na to spolehnout? Lze se spolehnout na to, že když nepoužiju selected, tak se při 'nevybrání položky' $_POST['test'] neodešle?
Jan Tvrdík
Profil
Jcas:
V selectu je vždy nějaká položka vybraná.
Jcas
Profil
Jan Tvrdík:
[#1] Jcas Tohle mi ukázalo, že to není pravda.
Jan Tvrdík
Profil
Jcas:
Špatně jsem si to přečetl. Nicméně <select> se size jinou než 1 stejně nikdy nepoužívej. Je to pro uživatele děsně matoucí. Nelze vizuálně poznat, jestli je to multiple nebo ne. Po označení nějaké položky nejde vybrat nic.
jenikkozak
Profil
Co se týká toho druhého příkladu, je v něm zřejmě chyba v měření - prohlížeče (pokud vím) posílají prvky hidden i text stejně, a proto je PHP stejně vyhodnocuje.
Jcas
Profil
jenikkozak:
jj, máš pravdu. Znova jsem testoval. Musel jsem někde udělat chybu. I skryté pole bez value odešle "".


jenikkozak:
[#3] Jcas. Odpověď na toto? Asi ne.

Závěr - použití <select>
Vždy pomocí selected nastavit výchozí hodnotu. Potom není třeba testovat existenci $_POST['select'], ale pouze vybranou hodnotu.
Jan Tvrdík
Profil
Jcas:
Potom není třeba testovat existenci $_POST['select']
Tak testovat existenci je potřeba vždy, zlý uživatel ti může poslat libovolný HTTP požadavek, tedy libovolné položky mohou chybět, nebo můžou mít hodnotu, kterou nelze normálně vybrat.
Jcas
Profil

Pozn. II: empty vz isset

Neexistují proměnou vnímá empty jako prázdnou. Je to logické. Když něco neexistuje, tak to nemůže obsahovat nějakou hodnotu.

1. existuje && je prázdná: isset==true, empty==true
2. existuje && není prázdná: isset==true, empty==false
3. neexistuje && je prázdná: isset==false, empty==true
4. neexistuje && není prázdná: isset==false, empty==true

Situace 3. a 4. je blbost. Pokud něco neexistuje, nemůže to nabývat hodnot "prázdná-plná"
Nicméně vypsání všech 4 možností mi ukázalo jednu jedinou situaci, kdy empty je schopna identifikovat situaci.

Proto lze v jednom případě použít empty i pro kontrolu existence.
if(isset($_POST['něco']) && !empty($_POST['něco'])) {...příkazy...}
// lze zkrátit
if(!empty($_POST['něco'])) {...příkazy...}
rafej
Profil
Jcas:
Proto lze v jednom případě použít empty i pro kontrolu existence.
>
>
>
if(isset($_POST['něco']) && !empty($_POST['něco'])) {...příkazy...}
// lze zkrátit
if(!empty($_POST['něco'])) {...příkazy...}

Nebude ti to fungovat, pokud má kontrolované pole hodnotu false nebo 0.
Jcas
Profil
rafej:
Musím říct, že jsem ještě nezažil situaci, kdy bych chtěl zpracovávat z odeslaného formuláře 0 nebo false.
Spíš absolutně nemám zkušenosti s podstrčením něčeho zákeřným uživatelem a proto se mi těžko odhalují tyto bezpečnostní chyby.

Druhá ukázka, kdy vynechávám testování existence (isset) a nechám to celé na empty.


if(isset($_POST['enter')) {   //testuji pouze zda byl formulář odeslán, nebo ne

   // odhalí jak situaci, kdy nějaká $_POST neexistuje, tak i jestli je prázdná
   if(empty($_POST['new_zvire']) || empty($_POST['new_skupina']) || empty($_POST['new_plemeno'])) {
            $hlaska[] = 'Vyplňte prosím všechna pole pro nové zvíře!';
        } else {    // všechna tři existují && jsou vyplněna
            ...příkazy...                        
            }
}
anonymníí
Profil *
Jcas:
Musím říct, že jsem ještě nezažil situaci, kdy bych chtěl zpracovávat z odeslaného formuláře 0 nebo false.
Ne? To jsi toho zažil málo :-) Počet dětí: 0. Dopravné: 0. Třeba.

Spíš absolutně nemám zkušenosti s podstrčením něčeho
Nepotřebuješ vědět, jak se podstrkává, důelžité je vědět, že kde čekáš jedničku (nebo v horším případě číslo), můžeš dostat cokoliv.
Jcas
Profil

Poznámka III. Podmínka if vs vrácené hodnoty z funkcí.


Dřív mi některé souvislosti nedocházeli moc rychle. Většinou jsem je odhaloval chybami. Kupodivu dnes (při častém opakováním všeho) už mi něco docvakne hned.
Dnes jsem po dlouhé době koukal na použití strpos() v podmínce if.
Prakticky hned mi došlo, že když strpos() vrací false, nebo číslo (int), tak že by se podmínce to int nemuselo líbit a také, že vrácenou 0 (výskyt na prvním místě) bude chápat jako false. Řešení jsem nehledal a měl jsem ho hned.
if(is_int(strpos($str, '-')))

Ale protože jsem si chtěl ověřit, jak to s tou podmínkou je, tak jsem znova začal pátrat. A ejhle - opět se mi potvrdilo, že vím houby.

Potvrdil se můj předpoklad, že if očekává hodnoty true-false.
viz:
"Očekává se, že hodnota nebo výsledek výrazu určující splnění podmínky bude typu boolean (logická hodnota)."
Očekával bych od PC chování ve stylu: if('string') If('string') ??? a co jako? Je roven něčemu? Nebo existuje? Nebo co? Trhni si nohou - podmínka nesplněna.
Jenže ono to tak není.

A php mi to hned ukázalo, když si samo proměnnou přetypovalo.
Konec konců, je to napsané zde
Takže jsem si udělal testík:
$str = '-string';
$vys = strpos($str, '-');    //int(0)
$vys2 = strpos($str, 's');    //int(1)
$vys3 = strpos($str, 't');    //int(2)

// int 1 a větší se sám přetypuje na true.
if($vys) {echo '$vys prošlo<br>';}    //false
if($vys2) {echo '$vys2 prošlo<br>';}    //true
if($vys3) {echo '$vys3 prošlo<br>';}    //true

// String se přetypuje také
if('0') {echo '"0" prošlo<br>';}    //false
if('str') {echo 'str prošlo<br>';}    //true

if($vys==0) {echo '== 0 prošlo<br>';}    //true
if($vys===0) {echo '=== 0 prošlo<br>';}    //true
if($vys=='0') {echo '== "0" prošlo<br>';}    //true
if($vys==='0') {echo '=== "0" prošlo<br>';}    //false

if(is_int($vys)) {echo 'is_int prošlo<br>';}    //true
if(is_int(strpos($str, ':'))) {echo 'is_int neprošlo<br>';}    //false

Trochu mě ale trápí ten "warning" v manuálu na použití ===. Chápu rodíl mezi == a === a chápu, že tím varováním chcou upozornit na to, že i když očekávám vrácenou hodnotu, tak může být vyhodnocena jako false, protože je vrácena 0.

Ale nechápu, proč je řešení ve ===. Když budu chtít zjistit, jestli je vráceno "něco", nebo false, tak mi to nepomůže a použiju něco jak is_int().
A pokud chci testovat, jestli je vrácena nula, tak projde jak if($vys==0), tak i if($vys===0).
A proč bych vrácený int testoval jak řetězec, abych musel testovat i typ?
juriad
Profil
Jcas:
Podmínkou s rovností == nejsi schopen odlišit nulu od false:
$x = false;
if ($x == 0) {
        echo "False == 0\n";
}

$y = 0;
if ($y == false) {
        echo "0 == False\n";
}

Funkce is_int ti bude fungovat, ale je to takové přes ruku. Když chceš testovat, že je něco false, tak se přece neptáš, zda to není celé číslo.
Jcas
Profil
juriad:
Když chceš testovat, že je něco false,... AHA. Zatím co když funkce vrací bool: true a false a já jsem zvyklí, že mohu testovat obojí:
if(true), if(!true), if(false), if(!false)
Tak pokud funkce vrací false, nebo nějakou hodnotu, tak to testování mohu zaměřit pouze na false.
$str = '-string';
$vys[] = strpos($str, '-');    //int(0)
$vys[] = strpos($str, 's');    //int(1)
$vys[] = strpos($str, 'b');    //false

foreach($vys as $var) {
if($var==false) { echo $var.' == false<br>';}
if($var===false) { echo $var.' === false<br>';}
if($var!=false) { echo $var.' != false<br>';}
if($var!==false) { echo $var.' !== false<br>';}
}
/* 0 == false
0 !== false
1 != false
1 !== false
== false
=== false
*/
Jcas
Profil

Poznámka IV - modulo

Poprvé jsem na to narazil zde.

Zbytek po dělení je ještě snadné pochopit.
4/2=2 a zbytek není žádný.
4/3=(zaokr.)1. Trojka se do čtyřky vleze pouze jednou a zbude 1. 3+1=4
7/3=(zaokr.)1. Trojka se vleze do sedmičky 2* a zbude jedna. 7-3*2=1 a 3*2+1=7


Aplikovat vzorec je také snadné. Co byl trochu můj problém (než jsem si udělal ukázku) bylo pochopit. Jak se to chová. Jak a kdy to aplikovat. K čemu takový výledek je a co nám vlastně takový výsledek prozradí.

A předevčírem mě dostalo toto.
[pre]

<img src="http://fakeimg.pl/200x130/282828/eae0d0/?text=Slon" id="obrazek2">
<br>
<a href="#" onclick="return zmena('obrazek2',[');">Zaměnit</a]http://fakeimg.pl/200x130/282828/eae0d0/?text=Slon','http://fakeimg.pl/200x130/282828/eae0d0/?text=Pes','http://fakeimg.pl/200x130/282828/eae0d0/?text=Potkan']);">Zaměnit</a>

function zmena(id, obrazky) {
    var obrazek = document.getElementById(id);
    var index = obrazky.indexOf(obrazek.src);
    index = (index + 1) % obrazky.length;
    obrazek.src = obrazky[index];
    return false;
}

Takže mi to nedalo a udělal jsem si tabulku, abych vlastně viděl, co nám takový zbytek po dělení dokáže ukázat. To co jsem nemohl pochopit je najednou krásně vidět. Jak se nám krásně opakují cykly 0.1.2.3 a 0.1.2.3 (jak 4 prvky pole)


https://docs.google.com/spreadsheets/d/1T3o06T8mOJjTA5g0pBVT-uboD_5cHUYnD8Z29FIVaZ0/edit?usp=sharing
juriad
Profil
Modulo se používá v několika situacích:
1) Při posunech skrz pole - pokud jsi na konci a jdeš doprava, chceš se objevit na začátku a to samé na opak. To se obvykle zapisuje jako:
$novyIndex = ($staryIndex + $posun + $delka) % $delka
Všimni si, že tam navíc příčítám $delku, to je z důvodu posunu doleva, kdy by jinak závorka mohla vyjít záporná. A v takovém případě není úplně jasné, co je modulo.
„When either a or n is negative, the naive definition breaks down and programming languages differ in how these values are defined.“ (wiki)
To přičtení nevadí neboť (A+B)%C = (A%C + B%C)%C a pokud B=C, pak B%C=0, a tedy je to celé rovné (A%C)%C = A%C.

2) Při periodickém provádění nějaké úlohy, třeba výpis třídy ke každému n-tému prvku tabulky. Pak stačí podmínka
if ($x % $n == 0) {...}
Nebo, pokud spouštíš interaktivně (PHP je zde blbý případ, ale syntaxi si vypůjčím) dlouhý výpočet ve smyčce, můžeš sledovat postup výpočtu:
for ($i = 0; $i < 1000000; $i++) {
  do_something_hard();
  if ($i % 1000 == 0) { # výpis jednou za 1000 iterací, aby to nezaplavilo log.
    echo "zpracováno $i prvků\n";
  }
}

3) Občas máš k dispozici generátor náhodných čísel, který generuje náhodné číslo v rozsahu 0 až 2^64 - 1. Ale ty chceš náhodné číslo v rozsahu 1 až 6 pro simulaci kostky. Jak na to?
Napřed chceme náhodné číslo v rozsahu 0 až 5 a to si následně posuneme přičtením jedničky.
$kostka = random() % 6 + 1

4) Některé celočíselné datové struktury využívají toho, že libovolné celé číslo lze vhodně rozložit. V případě van Emde Boasova stromu s kapacitou N se vyjádří každý prvek jako A = B * sqrt(N) + C, kde C < sqrt(N); tento rozklad lze spočítat takto: B = A / sqrt(N) a C = A % sqrt(N).
Je to základem struktury, která umožňuje extrémně rychlé operace s množinou: přidej prvek, smaž prvek, existuje prvek?, předchůdce, následník prvku vše v čase log log N (zlogaritmuj kapacitu a pak ji zlogaritmuj znovu). Toto v praxi asi nikdy nepotkáš :-)

Lepší než říkat zaokrouhlit je říct zakrouhlit dolů nebo říct celá část.
Jcas
Profil
Super vysvětlivky, to nemá chybu.

Vaše odpověď

Mohlo by se hodit

Příspěvky nesouvisející s webem budou odstraněny.

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: