Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: PHP ja lomakkeen uudelleenlataus

Sivun loppuun

JarkkoK [24.09.2014 16:21:58]

#

Lomakkeellani on pudotuslistoja tähän tyyliin:

<select name="Minuutit">
<option value="#">Minuutit</option>
<option value="00">00</option>
<option value="15">15</option>
</select>

Jos lomaketta täyttänyt on jättänyt pakollisia kenttiä täyttämättä ja yrittää lähettää lomakkeen tiedot, ladataan sivu uudestaan ja hänelle annetaan herja. Tässä tilanteessa lomakkeen tekstikentissä, checkboxeissa ja radiobuttoneissa säilyy vallan mainiosti se arvo, joka niissä oli lähetystä yritettäessä, mutta näiden pudotuslistojen sisältö "nollautuu" oletusarvolle.

Miten saisin pudotuslistoihin valitut arvot säilymään virheilmoituksen tapauksessa siten, että käyttäjän ei tarvitse valita niitä uudestaan korjattuaan virheen, josta herja johtui?

Eki++ [24.09.2014 16:36:52]

#

Javascriptilla.

<form action="..." onsubmit="return TarkistaLomake(this)">
...
<select id="minuutit" name="minuutit">
...
</select>
...
</form>
function TarkistaLomake(form) {
	if(form.getElementById("minuutit").selects.options[form.getElementById("minuutit").selects.selectedIndex].value == "#") {
		return false;
	}
	return true;
}

JarkkoK [24.09.2014 16:55:31]

#

Ei tää jostakin syystä toimi..?

-tossu- [24.09.2014 16:56:24]

#

Eki++: Lomakkeella ei ole metodia getElementById, eikä haetulla elementilläkään olisi ominaisuutta selects.

Viestin otsikosta saa käsityksen, että tarkistus on toteutettu palvelinpäässä PHP:llä ja palvelin virheen sattuessa palauttaa virheilmoituksen lisäksi esitäytetyn lomakkeen. Pudotusvalikosta voi valitun kohdan asettaa selected-attribuutilla, joka skriptin tulee asettaa valittuna olleeseen vaihtoehtoon.

<select name="Minuutit">
<option value="#">Minuutit</option>
<option value="00" selected>00</option>
<option value="15">15</option>
</select>

Eki++ [24.09.2014 17:02:38]

#

Hupsista... Näin siinä käy kun ei kokeile vaan kirjoittaa suoraan. Hyvä kun korjasit :)

No itse kysymykseen, omasta mielestäni ei pitäisi tehdä ainoastaan palvelinpään tarkistuksia, vaan pitää se ikään kuin backuppina. JS:llä tarkistukset ensisijaisesti.

Edit: No nyt mä en osaa kirjottaa edes normitekstiä oikein...

The Alchemist [24.09.2014 17:16:43]

#

Eki++ kirjoitti:

No itse kysymykseen, omasta mielestäni ei pitäisi tehdä ainoastaan palvelinpään tarkistuksia, vaan pitää se ikään kuin backuppina. JS:llä tarkistukset ensisijaisesti.

Täydellisen väärin. Ainoastaan palvelimen päässä tehdyillä validoinneilla on mitään väliä. Selaimessa tehtävät tarkistukset ovat vain käyttömukavuutta lisäävä tekijä, jos niitä käytetään oikein. (Muutoin ne vain aiheuttavat vitutusta.)

Kaikki syöte, mitä käyttäjältä luetaan, täytyy tarkistaa. Selaimessa olevat tarkitukset voi ohittaa, eikä hyökkääjän tarvitse edes käyttää nettiselainta vaan mikä tahansa alkeellinen skripti riittää. Siitä syystä palvelinsovelluksen täytyy varmistaa, että tiedot ovat oikein ja että käyttöoikeudet ovat kohdillaan.

Monesti näkee käytettävän reaaliaikaisia validointeja, jotka tarkistavat yksittäisen kentän pahimmillaan kesken syöttämisen ja alkavat valittaa epäkelvosta arvosta, koska käyttäjä on kerinnyt kirjoittaa sen vasta puoliksi. Tai kun rekisteröityessä kahden salasanakentän arvot tarkistetaan jo ensimmäisen kentän syöttämisen jälkeen -> takuuvarma virhe.

-tossu- [24.09.2014 17:20:16]

#

Eki++ kirjoitti:

JS:llä tarkistukset ensisijaisesti.

Tarkastukset tulee joka tapauksessa olla myös palvelinpäässä, sillä selaimessa olevat käyttäjä voi ohittaa joko tarkoituksella tai tietämättään skriptien ollessa poissa käytöstä. Tarkastukset, joilla ei ole merkitystä tietoturvaan, voidaan tosin poikkeustapauksissa suorittaa pelkästään selaimessa.

Selaimessa suoritettavan tarkastuksen tarkoitus on parantaa käytettävyyttä huomauttamalla virheistä ennen lomakkeen lähettämistä. Jos virheellisestä lomakkeesta näytetään alert-ikkuna käyttäjän painettua lähetysnappia, käytännössä mitään hyötyä ei saavuteta perinteiseen palvelinpään takastukseen verrattuna. Esimerkkisi tavoin toimiva tarkastus, joka ei edes huomauta virheistä vaan antaa kuvan rikkinäisestä sivusta, on vielä huonompi.

Metabolix [24.09.2014 17:21:22]

#

JS-purkka on toivottavasti historiaa. Nykyaikaista on lisätä required-määre ja laittaa ylimmän valinnan arvo tyhjäksi.

<select required="required">
	<option value="">Valitse jotain</option>
	<option value="00">00</option>
</select>

Firefoxissa valinnalle voi hauskasti lisätä attribuutit disabled ja selected, jolloin se on aluksi valittuna mutta siihen ei voi enää palata. En katsonut, mitä speksit sanovat tästä viritelmästä...

Jos tyhjäkin arvo on sallituissa vaihtoehdoissa, voi ylimmälle laittaa jonkin muun arvon ja required-attribuutin sijaan käyttää sitten pattern-attribuuttia sen hylkäämiseen.

JarkkoK [24.09.2014 21:54:59]

#

Metabolixin vinkkikään ei käsittääkseni ratkaise varsinaista ongelmaani.. vai enkö vain ymmärrä (mikä on täysin mahdollista)?

Lisäys:

Radio-buttonien kohdalla toimii tällainen parivaljakko:

<?php $luonne4val = (isset($_POST['TilaisuudenLuonne']) && $_POST['TilaisuudenLuonne'] == 'Muu') ? 'checked' : ''; ?>

<input type="radio" id="til4" name="TilaisuudenLuonne" value="Muu" <?=$luonne4val?>>Muu (tarkenna lisätiedoissa)

Mod. lisäsi kooditagit!

Metabolix [24.09.2014 22:11:33]

#

Unohdin sanoa, että tietysti merkkaat required-attribuutilla myös kaikki muut tarvittavat kentät lomakkeelta, jotta lomaketta ei koskaan lähetetä puutteellisena. Palvelinpuolen tarkistusten jälkeen sitten et tulosta mitään puolitäyttä lomaketta sivulle vaan tulostat vain virheilmoituksen, ja takaisin lomakkeeseen pääsee tarvittaessa normaaliin tapaan selaimen historian kautta.

Jos todella haluat tehdä sen ruman purkkaviritelmän, että virhesivulla tulostuu koko lomake uudestaan – mikä on mielestäni selaimen historian kannalta epäkäytännöllistä ja muutenkin rumaa –, joudut tarkistamaan tuolla samalla tavalla jokaisen optionin kohdalla, pitäisikö se valita.

<?php $minuutti = @$_POST["minuutti"]; ?>
<option value="00" <?= $minuutti === "00" ? "selected" : "" ?>>00</option>
<option value="15" <?= $minuutti === "15" ? "selected" : "" ?>>15</option>

Koodin pituutta voi tietenkin optimoida mm. tekemällä funktion option-elementin tulostukseen.

JarkkoK [24.09.2014 23:14:41]

#

En minä kyllä tuollakaan saa sitä toimimaan. Ehkä mun pitää luovuttaa oman yrittämisen osalta ja palkata joku joka osaa...

groovyb [25.09.2014 00:08:17]

#

Metabolix kirjoitti:

JS-purkka on toivottavasti historiaa. Nykyaikaista on lisätä required-määre ja laittaa ylimmän valinnan arvo tyhjäksi.

Nykyaikaista on kyllä mielestäni asettaa required ja muut validointisäännöt itse modeliin, josta tiedot asettuvat luotavaan lomakkeeseen automaattisesti (ja validoidaan joko sekä client että server -puolella, tai serverin päässä). Ei purkkailla erillisvalidointeja client puolelle, jotka sitten täytyisi erillisenä toteuttaa serverillä. Muutama suppea esimerkki:

Ruby on rails

# Jos halutaan myös client side -validation,
# ladataan tarvittava gem mukaan (gem 'client_side_validations')

# Model
class Person < ActiveRecord::Base
  validates :name, presence: true
  validates_numericality_of :age, less_than_or_equal_to: 100, greater_than_or_equal_to: 0
end

# Controllerissa...
def create
    person = Person.create(params[:person])
    if person.valid?
       person.save
       redirect_to :controller => 'index'
    end
end
<!-- View --->
<%= form_for @person,:url => {:action => "create"}, :validate => true do |f| %>
	<table>
    <tr>
        <td>
		    <%= f.label t :name %>
        </td>
        <td>
		    <%= f.text_field :name%>
        </td>
	</tr>
    <tr>
        <td>
		    <%= f.label t :age %>
        </td>
        <td>
		    <%= f.text_field :age%>
        </td>
	</tr>
  	<tr>
         <td>
    	    <%= f.submit "Create", :class => "button" %>
         </td>
  	</tr>
    </table>
<% end %>

C# MVC

//Jos halutaan client side validation ottaa mukaan,
//Asetetaan application starttiin
//HtmlHelper.ClientValidationEnabled = true;
//HtmlHelper.UnobtrusiveJavaScriptEnabled = true;

//Model
public class Person {

    [Required]
    [DisplayName("Name")]
    public string name { get; set; }

    [Range(0, 100)]
    [DisplayName("Age")]
    public int? age { get; set; }

}

//controllerissa...
[HttpPost]
public ActionResult Create(Person person)
{
    if (ModelState.IsValid)
    {
        db.Person.Add(person);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(person);
}
<!-- View --->
@using (Html.BeginForm("Create", "Persons")) {
     <table>
        <tr>
             <td>
                 @Html.LabelFor(model => model.name)
             </td>
             <td>
                  @Html.EditorFor(model => model.name)
                  @Html.ValidationMessageFor(model => model.name)
             </td>
        </tr>
        <tr>
             <td>
                 @Html.LabelFor(model => model.age)
             </td>
             <td>
                  @Html.EditorFor(model => model.age)
                  @Html.ValidationMessageFor(model => model.age)
             </td>
        </tr>
        <tr>
             <td>
                  <input type="submit" value="Create" class="button" />
             </td>
        </tr>
     </table>

}

Mitä taas tulee custom validointeihin (esim yksi checkbox ryhmästä tulee olla valittu), tämä toteutettaisiin samalla tavalla, validointiattribuuteilla modeliin.

qeijo [25.09.2014 14:48:27]

#

Sitten vielä PerfectHypertextPreprocessor:illa:

<?php

namespace Application\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Person {

	/**
	 * @ORM\Column(type="string", length=128)
	 */
	protected $name;

	public function getName() {
		return $this->name;
	}

	public function setName($name) {
		$this->name = $name;
	}
}
<?php

namespace Application\Form\Person;

use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;

class PersonForm extends Form implements InputFilterProviderInterface {

    const NAME_MAX_LENGHT = 100;

	public function __construct($form = null) {

		$this->add(array(
            'name' => 'name',
            'options' => array(
            	'label'  => 'Name',
            ),
			'attributes' => array(
				'required'	  => 'required',
                'maxlength'   => self::NAME_MAX_LENGHT,
            	'placeholder' => 'Person name',
            ),
        ));
	}

	public function getInputFilterSpecification() {

		return array(
			'name' 	=> array(
	            'required' 	 => true,
	            'validators' => array(
	              	array('name' => 'NotEmpty',
	                    'options' => array(
	                    	'messages' => array( \Zend\Validator\NotEmpty::IS_EMPTY => 'Syötä nimi',),
	                    ),
	               	),
	              	array('name' => 'StringLength',
	                    'options' => array(
	                    	'max'      => self::NAME_MAX_LENGHT,
	                    	'messages' => array( \Zend\Validator\StringLength::TOO_LONG => 'Nimi on oltava alle ' . intval(self::NAME_MAX_LENGHT) . ' merkkiä pitkä.',),
	                    ),
	               	),
	            ),
			),
       	);
	}
}
<?php $this->form->prepare (); ?>

<?= $this->form()->openTag($this->form); ?>

	<div class="form-group">
	    <?= $this->formRow($this->form->get('name')); ?>
	</div>

<?= $this->form()->closeTag($this->form); ?>

Mod. korjasi kooditagit, PHP ei ole HTML!

JarkkoK [25.09.2014 15:58:56]

#

Ongelma on korjattu.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta