Diskuze: Objektové programovanie
V předchozím kvízu, Online test znalostí PHP, jsme si ověřili nabyté zkušenosti z kurzu.


Martin Konečný (pavelco1998):17.1.2020 14:21
Ahoj, abys mohl dělat tzv. fluent interface (zřetězení metod), musíš v těch set() metodách vracet $this, tj.
public function vek($vek){
$this->vek = $vek;
return $this;
}
A potom ještě vypis() a VypisVaha() jsou metody, tedy ti chybí závorky, takhle by se to snažilo vypsat atributy $vypis a $VypisVaha a ty pochopitelně neexistují.
+20 Zkušeností
+2,50 Kč

MichalOškera:23.1.2020 15:03
Ďakujem za radu... a keby som ešte mohol trošku otravovať skúsil som napisať si kód na login a overenie uživatela... A chcem poprosiť čo je v nom zle kód funguje len myslím ako či je dosť bezpečný....
Data pred tým ako uložim do MySQL 8.0 šifrujem zatial cez base64 ale
šifrovanie mam zvlášť v triede, aby som to potom mohol vylepšiť nejaké
lepšie šifrovanie.
Trieda Data encode vracia 2 hodnoty jednu šifrovanú, ktorá je aj v DB a
druhú bez base64 ale skontrolovanú cez htmlspecialchars
Trieda Miss len vykresluje chyby čo uživatel nesplnil
Trieda Form vykresluje formular
Trieda MySQL pripaja ma cez PDO na databázu udaje vkladam cez bindValue.
Trieda Lang načitáva chybove hlašky adť.
Tu je kód:
class Admin{
private $Data;
private $MySQL;
private $Miss;
private $Form;
private $error;
public function __construct(){
session_start();
$this->Data = new Data;
$this->MySQL = new MySQL;
$this->Miss = new Miss;
$this->Form = new Form;
$this->Email = new Email;
$this->Lang = new Lang;
$this->idUser = $_SESSION['Admin_id'];
$this->url = $_SERVER['REQUEST_SCHEME']."://".$_SERVER['SERVER_NAME'];
}
public function login(){
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
// ENCODE DATA
$email = $this->Data->encode($_POST['email']);
$pass = $this->Data->encode_password($_POST['pass']);
/// IF VALIDATE FILTER
if(!filter_var($email['decode'], FILTER_VALIDATE_EMAIL)){
$error[] = $this->Lang->admin(1);
}
if(strlen($pass['decode']) < 5){
$error[] = $this->Lang->admin(2);
}
if(count($error) == 0){
$user = $this->MySQL->table('admin')->where('email="'.$email['encode'].'" && pass="'.$pass['encode'].'"')->select()->single();
}
if(empty($user['id'])){
$error[] = $this->Lang->admin(3);
}
// LOGIN
if(count($error) == 0){
session_start();
$code = md5($user['id'].$this->url.$user['email'].$user['pass'].time());
$_SESSION['id_User'] = $this->Data->encode_session($user['id']);
$_SESSION['login'] = $this->Data->encode_session(1);
setcookie('code_user', $code, time() + 1800, "/");
$this->MySQL->table('admin')->where('id='.$user['id'].'')->update($values = array("code" => $code));
header("Location:".$this->url."/rs/admin/", true, 301);
exit();
}else{
$news = $this->Miss->error($error);
$form = $this->Form->login($input = array("email" => $email['decode']));
}
}else{
$news = null;
$form = $this->Form->login(null);
}
return array($form, $news);
}
public function autorizacia(){
session_start();
$login = $this->Data->decode_session($_SESSION['login']);
$id_User = $this->Data->decode_session($_SESSION['id_User']);
if(filter_var($login, FILTER_VALIDATE_INT) && $login == 1){
$user = $this->MySQL->table('admin')->where('id="'.$id_User.'"')->select()->single();
if(filter_var($user['id'], FILTER_VALIDATE_INT) && !empty($user['id'])){
if($user['code'] == $_COOKIE['code_user']){
$code = md5($user['id'].$this->url.$user['email'].$user['pass'].time());
$this->MySQL->table('admin')->where('id='.$user['id'].'')->update($values = array("code" => $code));
setcookie('code_user', $code, time() + 1800, "/");
$autorizacia = 1;
}else{
$autorizacia = 0;
}
}else{
$autorizacia = 0;
}
}else{
$autorizacia = 0;
}
if($autorizacia == 0){
header("Location:".$this->url."/rs/", true, 301);
exit();
}
}
}
Martin Konečný (pavelco1998):23.1.2020 18:14
Ahoj, těžko posuzovat takhle z vytrženého kódu celé aplikace, ale na letmý pohled mi některé podmínky přijdou špatně testované, třeba
$user = $this->MySQL->table('admin')->where('id="'.$id_User.'"')->select()->single();
if(filter_var($user['id'], FILTER_VALIDATE_INT) && !empty($user['id'])) {
...
}
Nevím, co a jak přesně vrací ta metoda "single()", ale řekl bych, že když to uživatele najde, vrátí to pole s informacemi, a pokud ne, tak to vrátí FALSE nebo NULL. V takovém případě by ta podmínka byla lepší takhle:
if $user !== FALSE) {
...
}
ale záleží, co ta metoda vrací
Jinak jsou tam věci, které by v té třídě být neměly, jako třeba
přesměrování, ale tohle je sporné říkat, jelikož bys takhle postupně
stavěl celý webový framework Minimálně ale bych z těch tříd jen něco vracel - třeba pole
chyb nebo tak něco, a v řídícím skriptu až pak podle toho řešil, jestli
se má přesměrovat, něco zobrazit uživateli (chybová hláška, ...)
atd.).
Řídící skript je ta část kódu, kde voláš tu metodu login() nebo autorizacia(), tedy např.
$admin = new Admin();
if ($_POST) {
$result = $admin->login();
if (empty($result["chyby"])) {
echo "Přihlášení úspěšné";
} else {
echo "Při přihlášení vznikly chyby";
}
}
Ještě co se týká té "bezpečnosti", tak nevím, co přesně děláš za aplikaci, ale zdá se mi zbytečné něco šifrovat a ještě k tomu přes base64, ze kterého snadno zpětně ta reálná data získáš. Data v databázi se obvykle ukládají v surovém stavu, jen hesla se hashují, aby při případném ukradení dat nikdo ta hesla uživatelů nezjistil.
K čemu potřebuješ mít sloupec "code"?
Ahoj,
Single vracia ak nič nenájde prázdnu premenu. Ked niečo nájde vráti
Array ( [id] => 1 [email] => bWljaGFsb3NrZXJhQGdtYWlsLmNvbQ== [pass] => 27008213f0fbf8e4afe109d27887dc8b
=> a5cba0052a799208113ac519a0c14f29 )
A prečo je lepšia podmienka $user !== FALSE ako keď
kontrolujem pomocou filter_var
a zistujem ID či je číslo INT?
Som čítal, že dobre je mať plávajúci kód. Code mám vložený v cookie a v databáze. cookie má platnosť len 30 minut vždy pri obnove stránky sa predlžuje a mení sa code v DB aj cookie.
Viem že base64 neslúži na ochranu dát. Aplikoval som ho kvôli tomu, že dokáže nahradiť špecialne znaky ako ' " toto riešenie som našiel na konkurečnej stránke a keby bolo lepšie riešenie ako toto ošetriť, aby pri zápise napr do DB kód nebol narušený som za... Som samouk a programovanie mam zatiaľ len ako zábavu...
Martin Konečný (pavelco1998):23.1.2020 18:44
Ta "prázdná proměnná" znamená konkrétně co? NULL, FALSE, "", ... ? Je
to lepší proto, že když to nevrací pole, tak není dobré psát
$promenna["neco"], protože to jde psát jen u polí a u řetězců. Tedy tím
zbytečně riskuješ nějakou chybu a v databázi ID asi nebudeš mít něco jiného než číslo
(zvlášť pokud je sloupec INT a AUTO_INCREMENT), takže je ta podmínka na
kontrolu čísla zbytečná už z principu.
To "code" se mi zdá zbytečné, jelikož to, že je uživatel přihlášen, řeší session. Tyhle dočasné "tokeny" (code) se používají obvykle spíš jako taková autorizace/autentizace, pokud nejde použít session (třeba nemáš registrované uživatele, ale chceš něco zobrazit jen jednomu návštěvníkovi).
Martin Konečný (pavelco1998):23.1.2020 18:46
Data do DB je zvykem ukládat v takovém stavu, v jakém přijdou tzn. uvozovky, apostrofy a jiné
znaky by neměly být problém, ty ošetříš až při výpisu, ne při
zápisu. Tedy třeba funkci htmlSpecialChars() použiješ až když ten text na
webu vypisuješ, ne už když ukládáš do databáze.
Vracia hodnotu NULL. Ďakujem idem to zmeniť tie podmienky.
- Htmlspecialchars používam.
- Pridávam hodnoty do DB pomocou bindValue
bindValue(':'.$name, $value, $type);
a napr. pri $value bude čiarka tak zrazu vo funkcií budem mať 4 premné nie len 3. Alebo rozmýšlam zle?
Martin Konečný (pavelco1998):23.1.2020 19:10
Pokud ve $value bude čárka, tak to nic nezmění na volání funkce - je to stejné, jako kdybys napsal ručně třeba
funkce("hodnota, která, má, čárky")
Stále jde jen o jeden parametr, ne o čtyři, tedy to je v pořádku
$value = "hodnota, ",ktera ma, čarky";
Tak táto hodnota už bude zlá? alebo je jedno že može tam byť hoci jaký špecialny znak a bude to fungovať?
Martin Konečný (pavelco1998):28.1.2020 19:30
Tohle ti hodí chybu, řetězec je potřeba obalit do uvozovek nebo apostrofu. Pak je možné řetězce spojovat tečkou nebo čárkou, např.
$value = "hodnota, " , ", která má čárky";
Ale co se stane v příkladu u tebe, tak máš řetězec "hodnota, ", potom
spojovací znak (čárku) a pak nějaké "ktera", což se PHP asi pokusí
vyhodnotit jako konstantu a hodí ti to chybu nebo to prostě hodí chybu, že
to nedokáže zpracovat.
MichalOškera:29.1.2020 10:57
Je na to nejaká špecialna funckia alebo len str_replace
Spravne, na co? Ceho presne chces docilit a proc?
$a = '1'; $a = '2'; $a = '3';
$str = $a . $b . $c; echo $str.'<br>'; //123
$str = '123'; echo $str.'<br>';
$str = '1' . '2' . '3'; echo $str.'<br>';
$str = "12$c"; echo $str.'<br>';
$str = '1' . '2' . 3; echo $str.'<br>'; // tohle mozna vypise chybu
$num = 1 + 2 + 3; // 6
$str = "123"; // 123
$str = "1, 2, 3"; // 1, 2 ,3
$str = "\"1\", \"2\", \"3\""; // "1", "2" ,"3"
$str = '"1", "2" ,"3"'; "1", "2" ,"3"
$str = '\'1\', \'2\', \'3\''; // '1', '2' ,'3'
$str = "1
2
3"; // v html: 123, v source code: 1
2
3
$str = "1\n2\n3"; // v html: 123, v source code: 1
2
3 // totez jako prechozi priklad
$str = <<<EOF
"1" '2' 3
EOF; echo $str;
// vypise radek + "1" '2' 3 + radek do source code, html zobrazi mezera + text + mezera
echo '123';
var_dump(123);
var_dump('123');
var_dump('1', '2', '3');
var_dump('1'. '2'. '3');
var_dump($a, $b, $c);
// funkce pro nahrazeni
preg_replace
str_replace
strtr
htmlescapechars - vypis do html kodu
addslashes
nl2br - nahrazeni radkovani \n za <br> pro html
...
Das si
php/net/preg_replace
Podivas se co je pod nadpsem See also. A totez pro ostatni. Spoustu tech funkci nahrazuje ruzne znaky nebo tebou zadane, jakymsi odlisnym zpusobem. A dalse se podivas na ruzne priklady pouziti, co tam online jsou. Po stazeni dokumentace k php mas size zakladni verzi, ale priklady od uzivatelu jsou casto vetsim prinosem nez priklady od autora.
Univerzalni, ale pomalejsi zpusob je preg_replace.
Tve zadani je nejasne, je asi dalsich 300 zpusobu, prikladu, ktere je dobre
znat. Neni cas si vsechny vybavit a jeste marnit cas jejich vypisovanim
$str = <<<EOF
"1" '2' 3
EOF;
Jo, u tohoto zapisu tam muze byt jakykoliv text. A asi to tam to odradkovani
neprida, nejsem si ted jist.
Tam jde o to, ze ten text nahrazuje uzovozky a cely string je ukoncen prave tim
textem. cili treba EOF (end of file). Nebo treba jenicek. Zalezi i na velikosti
pismen
$str = <<<jenicek
"1" '2' 3
JENICEK
jenicek;
Vyhoda toho zapisu je prave v tom, ze nemusi kvuli php escapovat uvozovky.
Jo, a dalsi vec, kdyz treba pres php vypisujes js kod, tak se tam pouziva jeste escapovani uvozovek, protoze to jsou pravidla html
$str = ' <tag onclick="alert(\"123\");">';
echo $str;
$str = ' <tag onclick="alert(' . preg_quote('"123"'. ');">';
echo $str;
echo htmlescapechars($str);
Ale, jak jsem psal, univerzalne muzes pouzit preg_replace temer na vsechno.
Ja osobne jsem si vytvoril vlastni funkce, ktere jsem nazval jednotne
escape.
Protoze mne nebavilo stale hledat v manualu a zjistovat, cim se co ma escapovat.
Kdyz znam pravidla a vim, co chci videt na vystupu, tak potom s preg_replace je
to hracka.
function escapeHtml($str) {return htmlescapechars($str);}
function escapeUrl($url) {return urldecode($url);}
function my_nl2br($str) {return nl2br($str);}
function my_nl2br2($str) {return preg_replace('~\\n~', '<br>', $str);}
Aby som napr. odstranil alebo duplikoval tie apostrofy ono to bude potom aj fungovať
str_replace (' " ', ' """ ' , $text);
Idem zapisať hodnotu do MySQL pomocou formulára a v inpute bude text + nejaký apostrof tak pri zápisu PDO mi kód to rozdelí nie? PHP bude to rátať ako ďalšiu hodnotu
Martin Konečný (pavelco1998):29.1.2020 17:42
PHP to nevadí, vadí to max databázi v momentě, kdy bys to tam strkal přímo do dotazu, např.
$jmeno = "moje jméno s 'apostrofy'";
$pdo->query("INSERT INTO uzivatel VALUES ('{$jmeno}')");
ale pokud používáš parametrizované dotazy, což bys měl, tak to nevadí:
$jmeno = "moje jméno s 'apostrofy'";
$query = $pdo->prepare("INSERT INTO uzivatel VALUES (?)");
$query->execute(array($jmeno));
Viz Martin, pdo ma na to sve mechanizmy. Proto se nepouzivaji starsi ovladace
mysql_query.
V pdo mas 2 moznosti. Bud si sql dotaz sestavis sam, jako string. A nebo
pouzijes pomocne funkce, jako je prepare, bind, bindValue a pod, ktere maji
escapovani vestavene.
$query = "INSERT INTO uzivatel VALUES ('".$jmeno."')";
$pdo->query($query);
Neco takoveho bys mel pouzit jen v pripade, ze vis, co delas. Ze treba uz
nejakym filtrem predem z te hodnoty ty apostrofy odstranis nebo to prevadis na
integer cislo. Coz je treba muj pripad.
Ale, kdyz potrebuji neco slozitejsiho, tak pouziti podobnou funkci, jako jsi
udelal, mam ji nazvanou jako escapeSqlValue (pro data) nebo escapeSqlKey (pro
jmena tabulek a sloupcu). jde o to, ze pouzivam casto radu fitrovani a pouzivam
to v poli, tak to cyklem escapuji a nemusim resit slozite podminkovani kvuli
bindValue. Nektere fitrly treba uzivatel nepouzije a tak.
Zobrazeno 21 zpráv z 21.