Autor Zpráva
Nailen
Profil
Zdravím,
používám jeden americký systém, kde se teď potýkám s následujícím problémem.

Edituji záznam. Jsou tam nějaké pole, zatržítka,... Pak odesílám formulář metodou post. Pokud v poli Page Title mám původní anglický název stránky, tak se vše uloží v pořádku. Pokud není žádná změna, tak se nic nestane,... Jakmile ale do tohoto pole napíšu nějakou diakritiku, tak se sice také vše zapíše do DB, ale pokaždé, když dál uložit aniž bych cokoli změnil (nebo měnil jakékoli jiné pole), tak se toto pole Page Title (pole s diskritikou) znovu uloží do databáze. Takže zase se mi přes post předá hodnota editovaného pole a provedou se patřičné akce. Při každém ukládání, se ukládá informace do logu, takže tam jsem to zjistil, že se to takto chová.

Zde je ukázka kde se zapisuje do DB a do logu

//Changed title for page
    if($_POST['changeTitle'] != $pageDetails->title){
      $newTitle = Input::get('changeTitle');
      if ($db->query('UPDATE pages SET title = ? WHERE id = ?', array($newTitle, $pageDetails->id))){
        $successes[] = lang("PAGE_RETITLED", array($newTitle));
        logger($user->data()->id,"Pages Manager","Retitled '{$pageDetails->page}' to '$newTitle'.");
      }else{
        $errors[] = lang("SQL_ERROR");
      }
    }

Zde je příklad formuláře:

<form name='adminPage' action='<?=$us_url_root?>users/admin.php?view=page&id=<?=$pageId;?>' method='post'>
      <input type='hidden' name='process' value='1'>

...

<div class="row">
                <div class="col-sm-6 col-sm-offset-3">
                  <div class="form-group">
                    <label for="title">Page Title:</label> <span class="small">(This is the text that's displayed on the browser's titlebar or tab)</span>
                      <input type="text" class="form-control" name="changeTitle" maxlength="50" value="<?= $pageDetails->title; ?>" />
                    </div>
                  </div>
                </div>

...

<input type="hidden" name="csrf" value="<?=Token::generate();?>" >
                <a class='btn btn-warning' href="<?=$us_url_root?>users/admin.php?view=pages">Cancel</a>
                <input class='btn btn-secondary' name = "return" type='submit' value='Update & Close' class='submit' />
                <input class='btn btn-primary' type='submit' value='Update' class='submit' />
                </form>

Napadá někoho, čím by to mohlo být, že slova s diakritikou způsobí, že tato hodnota je vždy naplněna $_POST['changeTitle'] ?
Jakmile zruším diaktitická znaménka, tak vše začne fungovat správně.

Děkuji za nápady.
Kajman
Profil
Zkuste si do logu vypsat i původní hodnotu a pak zkontrolujte rozdíly - třeba budou vidět jen při porovnání binárních zápisů.
Keeehi
Profil
Nailen:
Napadá někoho, čím by to mohlo být, že slova s diakritikou způsobí, že tato hodnota je vždy naplněna $_POST['changeTitle'] ?
Otázka je položená špatně. Hodnota v $_POST['changeTitle'] je totiž vyplněná vždy, nezávisle na diakritice. To kde je rozdíl je v porovnání s hodnotou v $pageDetails->title.
Když použiješ toto, tak ti to přestane dělat updaty?
$newTitle = Input::get('changeTitle');
if($newTitle != $pageDetails->title){
Jestli ano, pak je to jasné, metoda Input::get('changeTitle') dělá nějaký preprocessing s daty a vrací tedy něco jiného než $_POST['changeTitle']
Nailen
Profil
Kajman:

Dobrý den, na webu je zobrazené písmeno ý ale v db je uloženo &yacute;
To bude ten rozdíl, že?


Keeehi:

Dobrý den, když jsem připsal tu vaši podmínku, tak to začalo fungovat tak jak má.
Zjistím někde co dělá ta metoda Imput::get a jak je nadefinovaná? Jak bych to měl najít ve zdrojáku? Díky
Keeehi
Profil
Předpokládám, že jde o starý Laravel. Pak Input:get je fasáda na Request->input.
Předpokládám, že někde něco převádí znaky s diakritikou na entity. Zdá se mi divné, že by to dělalo zrovna Input::get. Ovšem ona spousta věcí v Laravelu funguje tak nějak magicky. Proto ho taky odmítám používat.

Mimochodem, myslím, že Input::get je naposledy běžně používané ve verzi 4.2. Ve verzi 5 to je značeno za deprecated a od verze 6 to neexistuje. Respektive to bylo nahrazeno Request::input.
Nailen
Profil
Keeehi:
Děkuji za vysvětlení. I když se musím přiznat, že toto je nad moje aktuální schopnosti v PHP. Takže se zeptám ještě takto. Když mi to teď s podmínkou, kterou jste mi poradil funguje, mám to dál řešit, nebo pokud mi to takto stačí, tak to dál nemám řešit?
Je nějaký jednoduchý způsob, jak docílit toho, aby mi to diakritiku nepřevádělo na entity? Aby to bylo čitelné v databázi, tak jak se to do DB nahrálo při importu?
Keeehi
Profil
Nailen:
Je nějaký jednoduchý způsob, jak docílit toho, aby mi to diakritiku nepřevádělo na entity?
Asi ano, ale jak jsem psal, kvůli té jeho magii s Laravelem nepracuji, takže ti přímo neporadím. Obecně, dej si ručně do databáze čistá data a pak zjisti, kde se ti to poprvé převedlo na entity. Pokud tohle místo najdeš, mělo by být možné zjistit, jak tomu zabránit.
Nailen
Profil
Keeehi:
OK, díky. Budu pátrat. Ještě se zeptám. Když si vypisuji hodnoty přes echo, tak nikde nenarážím na entity až v DB. Mám je vypisovat nějak jinak, abych to odhalil? Děkuji
Kajman
Profil
Jaké parametry používáte při vypisování do html stránky ve funkci htmlspecialchars?
Nailen
Profil
Kajman:
našel jsem toto: $query = htmlspecialchars(Input::get('query'));

a také jsem našel tu třídu:

class Input {
    public static function exists($type = 'post'){
        switch ($type) {
            case 'post':
            return (!empty($_POST)) ? true : false;
            break;

            case 'get':
            return (!empty($_GET)) ? true : false;

            default:
            return false;
            break;
        }
    }

    public static function get($item){
        if (isset($_POST[$item])) {
            /*
            If the $_POST item is an array, process each item independently, and return array of sanitized items.
            */
            return self::sanitize($_POST[$item]);

        } elseif(isset($_GET[$item])){
            /*
            If the $_GET item is an array, process each item independently, and return array of sanitized items.
            */
            return self::sanitize($_GET[$item]);
        }
        return '';
    }

    public static function sanitize($item){
        if (is_array($item)){
            foreach ($item as $key => $itemValue){
                $postItems[$key]=self::sanitize($itemValue);
            }
            return $postItems;
        }else{
            return trim(htmlentities($item, ENT_QUOTES, 'UTF-8'));
        }
    }
}
Keeehi
Profil
Nailen:
Za to převádění na entity je zodpovědná ta funkce htmlentities.
Jinak tahle sanitizace je pěkná prasárna. Data z formuláře by měl kód dostat ve víceméně čisté podobě a ne po tom co to projde tímto. Uživatelský vstup je samozřejmě vždy potřeba escapovat, ale ne tímto způsobem, který vůbec nebere kontext do úvahy.

Pokud chceš vynechat to escapování, pak stačí ten Input::get prostě nepoužit a šlápnout si na post data napřímo.
if($_POST['changeTitle'] != $pageDetails->title){
      $newTitle = $_POST['changeTitle'];

Samozřejmě, jelikož to teď není escapované, mělo by se to escapovat na výpisu. Jak? No to záleží dle kontextu.
Nailen
Profil
Keeehi:
Skvělé, děkuji za vysvětlení. Upravil jsem to. Ukládání funguje jak má. V DB mám znaky s diakritikou, takže nyní jsem spokojen.

Píšete, že by přesto mělo proběhnout escapování na výpisu. Mohu ještě poprosit o vysvětlení jak je to přesně myšleno. To znamená, že bych měl obsah z DB před zobrazením na webu prohnat přes nějakou funkci, která daný obsah (text) ještě escapuje?

Uživatelský vstup těchto dat je pouze na úrovni administrátorského rozhraní, takže by v těchto Titlech nemělo být nic nežádoucího.
Keeehi
Profil
Nailen:
To znamená, že bych měl obsah z DB před zobrazením na webu prohnat přes nějakou funkci, která daný obsah (text) ještě escapuje?
Ano. Důležité to je u dat nad kterými nemáš kontrolu. U dat z administrace to nemusí být nutnost, ale je to dobrá praxe. On se v budoucnu ten zdroj může změnit a mezitím zapomene, že se to někde vypisuje neošetřené. Proto je dobré escapovat vždy každý výstup.
Nailen
Profil
Keeehi:
OK, díky. Pokud tedy nemám používat htmlspecialchars tak doporučíte mi něco co je lepší varianta?
Kajman
Profil
Funkci htmlspecialchars máte používat až při výpisu všech dat do html stránky. Nemáte ji jen používat pro uložení dat do databáze.
Nailen
Profil
Kajman:
OK, děkuji moc za vysvětlení.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

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

0