Tekenset en -codering

Verrassend vaak nog krijg ik (zelfs van IT professionals) de vraag waarom hun website van de ene dag op de andere plots “vreemde” tekentjes vertoont op plaatsen waar je een é of een ç of aan µ verwacht. Het gebruik van karaktersets is namelijk even eenvoudig als belangrijk …

Welke karakters een browser op ons scherm plaatst wordt bepaald door de tekenset en tekencodering. De tekenset is de verzameling van beschikbare karakters.  Ons alfabet zou als een tekenset van 26 tekens beschouwd kunnen worden.  UNICODE is een voorbeeld van een zeer veel gebruikte tekenset in de IT wereld, deze set probeert alle karakters te verzamelen die nodig zijn om quasi elke taal compleet te kunnen weergeven. Tekencodering is dan weer de manier om een karakter op te slaan in de vorm van bytes.  UTF-8 is een veel gebruikte vorm van tekencodering.

In praktijk worden de termen tekenset en tekencodering door elkaar gebruikt. Zo zal je vaak lezen dat een tekst is opgebouwd met de UTF-8 tekenset, … niet 100% correct maar iedereen begrijpt wat er bedoeld wordt.

Als onze webpagina gecodeerd is op basis van tekstcodering A en de browser probeert ze te decoderen op basis van tekstcodering B dan krijgen we de gekke tekens op het scherm. Het komt er dus op aan tekstcodering A te gebruiken en de browser duidelijk te maken dat we A gebruiken en niets anders. Elke deftige teksteditor voorziet in de mogelijkheid om de codering te bepalen, zelfs Kladblok van Windows. Zorg er dus voor dat je goed weet welke tekstcodering je gebruikt. (UTF-8 is absoluut aan te bevelen !!).

image

1. De webserver kan deze informatie meegeven in de vorm van een “Content-Type” HTTP header. Zo’n header instellen kan in de config bestanden van de meeste webservers (vb .htaccess in een apache webserver)

AddCharset UTF-8 .html

of kan door een scripting taal voorzien worden (vb. PHP).

<?php
header('Content-Type: text/plain; charset=UTF-8');
?>

2. De HTML pagina  kan deze informatie meegeven in de vorm van een “META” – tag

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

De eerste manier geniet de voorkeur maar is niet altijd haalbaar, daarom is de tweede manier een absolute must have in elk HTML document.  Als de tekstcodering niet opgegeven wordt moet de browser raden welke tekstcodering hij moet gebruiken. Afhankelijk van browser tot browser en van webpagina tot webpagina lukt dat soms wel, soms niet.

Bij statische pagina’s zijn de problemen onmiddellijk duidelijk en mits wat trial en error kan elk aapje het in orde krijgen.  Dynamische webpagina’s die tekst ophalen uit een databank staan echter voor heel wat meer problemen.

Wanneer je tekst in de databank wil invoeren moet er tussen je programmeertaal en de databank afgesproken worden welke taal je spreekt tijdens de communicatie, de databank moet de data opslaan op basis van een karakterset die alle karakters bevat die jij wil gebruiken en tot slot … als je data ophaalt uit de databank moet je die krijgen in het formaat van je HTML pagina.  Immers als je bovenaan je pagina aangeeft dat je HTML pagina in “UTF-8”  gecodeerd is moet je databank er niet zomaar wat ISO 8859-1 komen tussen gooien.

Tekst aanbieden aan je databank doe je vaak nadat iemand een HTML formulier gepost heeft naar een pagina. Je gaat de $_POST[‘xxxx’] al dan niet na bewerking in de databank opslaan.  De $_POST[] variabelen gebruiken de tekstcodering van de HTML/PHP pagina.   Verwittig je databank dat je UTF-8 tekst gaat aanleveren :

mysql_set_charset(‘utf8’);

Voor elk veldje in elke tabel van elke databank van elke MySQL server kan je bepalen hoe tekst wordt opgeslagen (= met welke codering). Kies een karakterset die alle karakters bevat die je wil opslaan in je databank, bij voorkeur dezelfde tekenset als die die je in je HTML/PHP pagina gebruikt en die die je gebruikt om te communiceren met de databank.  Je kan de tekencodering (de Collation) bepalen op 4 niveau’s. Het laagste niveau heeft prioriteit. Als je dus je tabel collation instelt op “Latin-1” maar je veld op “UTF-8” dan zal de tekst in dat veld met UTF-8 gecodeerd worden.  Stel je geen specifieke collation in voor een veld dan wordt de tabel collation genomen. Is er geen specifieke tabel collation ingesteld dan wordt de databank collation genomen enz …

Tot slot … als je een HTML/PHP Pagina hebt die in UTF-8 gecodeerd is dan wil je dat de tekst uit de databank ook in UTF-8 aangeleverd wordt.  Dat doe je ook met

mysql_set_charset(‘utf8’);

Dat problemen soms pas “op termijn” boven water komen is normaal. De meeste vormen van tekstcodering gebruiken dezelfde codering voor veel voorkomende karakters als a-z, A-Z, 0-9, enz … De codering wordt pas afwijkend op het ogenblik dat je karakters gebruikt als è, à, é, µ, ~, ..

Samenvattend : consequent één vorm van tekst codering gebruiken voor zowel de opmaak van de HTML/PHP pagina, communicatie met de databank als opslag in de databank combineren met deze tekstcodering duidelijk definiëren op alle niveau’s is de enige garantie op een website zonder gekke tekentjes !

Toch nog problemen met tekenset en tekencodering? Contacteer ons !

Grootte POST variabele in PHP

Ondertussen is PHP versie 5.3.9 al eventjes op de markt en meer en meer servers beginnen deze versie te gebruiken. Wie dan niet aandachtig de changelog naleest kan plots problemen krijgen met het posten van grote forms.  Plots is de form “te groot”.

In een spontane reflex gaan we kijken naar de “post_max_size” parameter in php.ini maar die blijkt ruim voldoende te zijn.  Sinds PHP 5.3.9 werd een nieuwe parameter toegevoegd nl. “max_input_vars” die het maximaal aantal input variabelen standaard beperkt tot 1000. Wil je meer dan 1000 values posten (toch even nadenken over je performance !!) dan moet je deze parameter in PHP.INI of via INI_SET aanpassen.

Gebruik je de Suhosin patch op je servers dan moet je ook de parameters “suhosin.post.max_vars” en “suhosin.request.max_vars” aanpassen.

Lazy evaluation in PHP, ASP.NET, …

Wanneer ik gevraagd word als consultant op vlak van performance tuning van maatsoftware is er één zaak die bijna elke keer terugkomt. Heel wat programmeurs maken onvoldoende gebruik van Lazy evaluation. Quasi elke programmeertaal voorziet standaard in lazy evaluation. Eenvoudig gezegd komt het hierop hier dat een programmeertaal stopt met vergelijkingen evalueren op het ogenblik dat het toch geen zin meer heeft. Een voorbeeldje.

Je schrijft een functie die een getal als input krijgt en als dat getal ofwel deelbaar is door 4 ofwel een priemgetal dan returned de functie true anders false.

if (($input % 4 == 0) || (ispriemgetal($input)))
{
    return true;
}
else
{
    return false;
}

Als onze invoer variabele gelijk is aan pakweg 12 dan zal het tweede gedeelte van de if constructie niet meer uitgevoerd worden omdat het toch geen zin heeft, wat het resultaat ook is van “ispriemgetal($input)” het eindresulaat is toch true.  Het is dus belangrijk om de minst cpu intensieve vergelijking eerst te plaatsen zodat de meer cpu intensieve vergelijkingen niet uitgevoerd worden als dat niet echt nodig is. Ons voorbeeld is dus correct vanuit een performance tuning standpunt omdat we ervan mogen uitgaan dat controleren of een getal deelbaar is door 4 minder kracht vergt dan controleren of een getal een priemgetal is.  Dit zou minder goed zijn :

if ((ispriemgetal($input)) || ($input % 4 == 0))

In dit concreet geval zou het trouwens echt zinloos zijn omdat een priemgetal per definitie niet deelbaar is door 4 of een getal deelbaar door 4 per definitie geen priemgetal kan zijn.

PHP, JSON en Javascript

Wie vandaag de dag niet minstens een handvol van die hippe Ajax gif’s heeft staan draaien op zijn website is niet meer mee met deze tijd. En toch krijg ik dagdagelijks de vraag hoe dit correct te implementeren. Easy … toch ?

<img src="ajax.gif" alt="How cool is this" /> <!-- Yup, developpers humor -->

Zelfs als je er nog wat asynchrone communicatie bij wil blijft het eenvoudig. Ongeacht of je nu PHP, ASP … gebruikt als server scripting taal en of je nu jquery, prototype, … gebruikt als client side scripting taal. Bij voorkeur gebruik je JSON als formaat om gegevens te transporteren.

JSON is even eenvoudig als krachtig.  Je hebt altijd paren van “identifiers” en “values” die van elkaar gescheiden worden door middel van een : (dubbel punt). Verder worden objecten omsloten door { }, array’s worden omsloten door  [ ], Strings worden omsloten door dubbele quotes.   En op eenvolgende paren van identifier+value worden van elkaar gescheiden door een komma. Dit is even kort door de bocht maar is toch wel 95% volledig.

Omdat voorbeelden vaak veel meer zeggen dan al te veel bla bla, dit stukje PHP code waarin ik op een geheel onorthodoxe wijze een aantal objecten aanmaak.

   1:    class Person
   2:    {
   3:        public $name;
   4:        public $givenname;
   5:        public $age;
   6:        public $adult;
   7:    }
   8:  
   9:    class Family
  10:    {
  11:      public $father;
  12:      public $mother;
  13:      public $kids;
  14:    }
  15:  
  16:    $a = new Family();
  17:  
  18:    $a->father = new Person();
  19:    $a->mother = new Person();
  20:    $a->kids = array();
  21:  
  22:    $a->father->name = "Depuydt";
  23:    $a->father->givenname = "Dieter";
  24:    $a->father->age = 27; // I Wish
  25:    $a->father->adult = true;
  26:  
  27:    $a->mother->name = "My";
  28:    $a->mother->givenname = "Wife";
  29:    $a->mother->age = 27;
  30:    $a->mother->adult = true;
  31:  
  32:    $b = new Person();
  33:    $b->name = "Depuydt";
  34:    $b->givenname = "Daughter";
  35:    $b->age = 4;
  36:    $b->adult = false;
  37:  
  38:    $c = new Person();
  39:    $c->name = "Depuydt";
  40:    $c->givenname = "Son";
  41:    $c->age = 2;
  42:    $c->adult = false;
  43:  
  44:    array_push($a->kids, $b);
  45:    array_push($a->kids, $c);

Dit resulteert dus in een family object “a”, dat 4 person objecten bevat, 2 los in het object (father en mother) en 2 in een array (kids).  We hebben zowel tekst, getallen als booleans.  Dit omzetten in JSON geeft ons

   1:  {
   2:    "father":
   3:        {"name":"Depuydt","givenname":"Dieter","age":27,"adult":true},
   4:  
   5:    "mother":
   6:        {"name":"My","givenname":"Wife","age":27,"adult":true},
   7:  
   8:    "kids":
   9:     [
  10:        {"name":"Depuydt","givenname":"Daughter","age":4,"adult":false},
  11:        {"name":"Depuydt","givenname":"Son","age":2,"adult":false}
  12:     ]
  13:  }

De omzetting van PHP object naar JSON string kan je volledig zelf programmeren maar in PHP is dat niet nodig, er bestaat een kant en klare functie die het werk voor ons doet :

   1:  json_encode($a);

Nu rest ons enkel nog het object in JSON formaat op te vragen, de tijd dat het duurt om de informatie te ontvangen ons uber hip ajax symbooltje te tonen en uiteindelijk eens de (json) informatie ontvangen er iets mee aan te vangen.  Dit kan met elke vorm van client side scripting, hier gebruiken we de prototype library.

In onderstaand voorbeeldje gaan we ervan uit dat de HTML pagina waarin we werken een DIV met ID “json” heeft.   We vragen onze PHP pagina op waarin onze object structuur zit alsook het commando om het object om te zetten in json. Het resultaat daarvan wordt gewoon ge-echo’d.

   1:  <script type="text/javascript">
   2:  var url = 'index.php';
   3:  
   4:  new Ajax.Request(url, {
   5:      method: 'get',
   6:      onLoading : function() {
   7:          $('json').innerHTML = "<img src='ajax.gif' alt='How cool is this' />";
   8:      },
   9:      onSuccess: function(originalRequest) {
  10:          var invoer = originalRequest.responseText.evalJSON();
  11:          $('json').innerHTML = invoer.kids[1].givenname;
  12:      }
  13:  });
  14:  </script>

Op lijn 6 zie je dat we bij het begin van de aanvraag alvast ons ajax.gif symbooltje aan de gebruikers presenteren.

Op lijn 9 ontvangen we als alles goed gaat de JSON string, die we verwerken met evalJSON() en het resultaat daarvan opnieuw kunnen gaan gebruiken als objecten/arrays. zoals je kan zien op lijn 11.