[Alku]
Testaa CSS-oppaan navigoinnin toimivuutta!
   
 
Hae sivuiltani:
[Apua]

Selaintunnistukset

PHP:llä selaimia tunnistettaessa perusongelma on siinä, että selaimia voidaan tunnistaa vain selainten tunnistautumismerkkijonoista (UA strings) PHP:n sisäänrakennettujen muuttujien, esim. $HTTP_USER_AGENT avulla.

<?php print $HTTP_USER_AGENT; ?>

Yllä mainittu komento tulostaa selaimesi tunnistusmerkkijonon, mikäli Web-palvelimen asetukset sen sallivat. On kuitenkin paras luoda tähän tarkoitukseen uusi muuttuja, esim. $userBrowser = $_SERVER['HTTP_USER_AGENT']; (käytän esimerkeissäni $userBrowser-muuttujaa).

Palvelinkohtaisia huomautuksia:

  1. Palvelimen PHP-asetuksissa saattaa olla register_globals=Off. Tällöin $HTTP_USER_AGENT ei toimi. $HTTP_USER_AGENT jne. ovat sisäänrakennettuja globaaleja, joiden näkyvyysalue kattaa koko sovelluksen (ts. ne ovat sovellusmuuttujia). Ne ovat käytettävissä kaikillä sivuilla ilman sen kummempia määrittelyjä. Sen sijaan kun koodissa määrätään muuttujan global sanalla globaaliksi, määritetään sen vaikutusalueeksi ko. skriptisivun (tosin esim. include-funktion avulla tällä voidaan jäljitellä sovellusmuuttujia). $_SERVER muuttujaa käyttämällä voi luoda uusia skriptikohtaisia yleismuuttuja. Esim. koodin

    <?php
    global $userBrowser;
    $userBrowser = $_SERVER['HTTP_USER_AGENT'];
    print $userBrowser;
    ?>
    pitäisi tulostaa selaimesi tunnistusmerkkijonon, joka näkyy tämän tekstin alapuolella:
    CCBot/2.0 (http://commoncrawl.org/faq/)

Eräs ongelmallisimmista tunnistettavista on Netscape 4.x -sarjan selaimet. Ne kun antavat käytännössä hyödynnettäväksi vain Mozilla ja sen versionumeron. Alla esimerkki erään Netscape 4.x -selaimen antamasta tunnistusjonosta:

Mozilla/4.79 [en] (Win98; U)

Tunnistusjonoa Mozilla/4. käyttävät useimmat markkinoilla olevat selaimet, joten muut selaimet tulee raakata pois.Alla koodi, jossa ensin funktion stristr() avulla tunnistetaan MS IE, Mozilla Gecko ja Opera -selaimet sekä Mozilla/4 merkkijono (kyseistä funktiota käytettäessä ei ole merkitystä ovatko kirjaimet isoja vai pieniä).

$MSIE = (stristr($userBrowser, "MSIE") || stristr($userBrowser, "Internet Explorer")); /* Funktion stristr() ensimmäinen argumentti on merkkijono, josta etsitään. Jälkimmäinen on alimerkkijono, jota haetaan. */
$Opera = stristr($userBrowser, "Opera");
$Gecko = stristr($userBrowser, "Gecko");
$Moz4 = stristr($userBrowser, "Mozilla/4");
$NN4 = ($Moz4 && !$MSIE && !$Gecko && !$Opera);

Tunnistamatta jäävät sellaiset selaimet, joiden tunnistusmerkkijonossa mainitaan Mozilla/4. ja jotka eivät ole MS IE, Opera tai Netscape -selaimia. On kuitenkin mahdollista tunnistaa selaimet tietyltä väliltä. Mielekäs väli olisi tunnistaa selaimet, jotka ovat Mozilla/4.00 uudempia ja Mozilla/5.0 vanhempia. Nämä selaimet voidaan tunnistaa käyttämällä floatval() funktiota, jonka avulla merkkijonot voidaan kääntää desimaaliluvuiksi (käytetään engl. nimitystä double):

$Moz4All = ((floatval(substr(stristr($userBrowser, "Mozilla"),8, 3)) > 4.0) && (floatval(substr(stristr($userBrowser, "Mozilla"),8, 3)) < 5.0)); /* Ensimmäinen substr() funktion arvo määrittää mistä kohtaa merkkijonon alusta alimerkkijono alkaa ja jälkimmäinen määrittää merkkijonon pituuden. Jos arvon loppuun tulisi välilyönti ja kirjaimia, ne eivät haittaa, sillä niiden mahdollisuus on otettu huomioon funktiossa. ctype_digit() avulla suoritettua arvotarkistusta ei tarvita. Saamani s-postin mukaan PHP:n float-tietotyypissä (liukuluku) tulee varmistaa, että tietotyyppi on liukuluku. Vertailevan liukuluvun voi myös pilkkoa explode()-funktiolla pisteen kohdalta ja vertailemalla erikseen syntyviä kokonaislukuja (ts. pisteen etu- ja jälkipuolta) intval() funktiota käyttäen. */

Palvelinkohtaisia huomautuksia:

  1. Kaikki palvelimet eivät tue floatval() funktioita, sillä se on tuettu PHP 4.2.0 lähtien, mutta toimivuuden saa aikaiseksi vanhemmissa PHP-versiossa käyttäjän määrittelemällä funktiolla.

    php.net: floatval

Joissakin tapauksissa tarvittava käännösfunktio on intval() (esim. Gecko/20001108 varten (intval(substr(stristr($userBrowser, "Gecko"),6, 8))). Selaintarkistukseni ei ota huomioon aivan kaikkia selaimia, mutta useimmat kuitenkin. On myös huomattava, että jotkin selaimet käyttävät joko MS IE:n tai Mozilla Gecko -selainten esityskonetta, jolloin ne otetaan huomioon MS IE ja Gecko -selaimia etsittäessä. Maininnan arvoisia selaimia ovat Linux käyttöjärjestelmässä käytettävissä oleva Konqueror ja Macissa Safari. Ne voi tunnistaa aivan samaan tapaan kuin muutkin selaimet. Alla on eräs Safarin tunnistusmerkkijono:

Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/48 (like Gecko) Safari/48

JavaScript-koodauksessa voitaisiin kysyä if (document.layers), jota tukee vain Netscape 4.x -sarjan selaimet. Ongelmana olisi kuitenkin se, että kyselyjä ei voitaisi laittaa muuttujiksi (esim var 4NN4 = (...);) ja Netscape 4.x täytyy huomioida erityisellä tavalla.

Toinen ongelmakohta on tunnistamatta jääneet DOM-selaimet. JavaScript-koodauksessa voidaan kysyä if (document.getElementById) eikä selainten tunnistusmerkkijonoja tarvita. Ei ole mitään mieltä yrittää selvittää mitkä kaikki selaimet tukevat DOMia. Jos esim. halutaan määritellä DOMia tukeville selaimille tietty CSS tunnistuksessa voidaan edetä seuraavasti:

  1. Määritellään MS IE:n selainkohtaista DHTML:ää ja DOMia tukeville selaimille yhteinen CSS.
  2. Kyseinen CSS laitetaan sivulle siten, että Netscape 4.x ei sitä lue. Mielestäni helpoiten asiasta selviää kirjoituttamalla kommentit sellaisten CSS-tiedostojen ympärille, joita Netscape 4.x:n ei kuulu lukea:
    <?php
    include('...');
    /* Tiedosto sisältää muuttujamääritykset. */

    if ($NN4){echo "<!--\n";}?>

    <link rel="stylesheet" ...
    ...

    <?php if ($NN4){echo "-->\n";}?>
  3. Selainkohtaiset lisätiedostot haetaan PHP:llä (mallitiedosto[S] ja siihen liittyvät muuttujamäärittelyt[S]).

JavaScript ja PHP tunnistuksia voidaan myös yhdistellä. Ensin niin pitkälle kuin mahdollista PHP:llä ja selaimille, joille se ei sovellu tuotetaan tarvittava JavaScript-koodi tai viittaus JavaScript-tietostoon:

...
else {
echo "<script language=\"JavaScript\" type=\"text/javascript\" src=\"../Navigoinnit/AdviceBrowserSpecificCSS.js\"></script>"; }

Tavanomaiset (X)HTML-selainten ohella on myös WML-dokumenttien selailemiseen luotuja kännykkäselaimia. WML 1.x muistuttaa niin paljon XHTML:ää, että pienellä moduloinnilla on mahdollista luoda samasta materiaalista sekä WML 1.x:ää että (X)HTML:ää ymmärtäville selaimille eri versiot.

WML 1.x sisältää HTML:ään verraten vähän elementtejä. Jos sisältö on yhteinen, käytetään elementtejä ja attribuutteja, joita WML 1.x -selain ei tunnista, mutta joista ei pitäisi olla sille haittaa. WML:ssä on puolestaan elementtejä ja attribuutteja, jotka eivät kuulu XHTML:ään. Seuraavat elementit ovat yhteisiä (WML 1.2 elementeistä on myös englanninkielinen taulukko[S]):

Mikäli WML-selaimia tuetaan ainakin seuraavat asiat tulee ottaa huomioon:

Tavanomaisen selaintunnistuksen sijaan WML-selaimet voitaisiin periaatteessa tunnistaa mime-tyypin perusteella eli sen perusteella millaisia tiedostotyyppejä selaimet suoraan (ilman lisäosia) tukevat. Muuttujina käytettääisiin joko $_SERVER['HTTP_ACCEPT'] tai $HTTP_SERVER_VARS['HTTP_ACCEPT'] muuttujaa (jälkimmäinen välttämätön, jos globaaleja muuttujia ei sallita). Alla on testi, joka ilmoittaa toimiiko systeemi käyttämälläsi selaimella riittävässä määrin. Testi myös listaa selaimesi ilmoittamat mime-tyypit (alla testikoodi):

Selaimesi ilmoittaa palvelimelle riittävän määrän tuettuja mime-tyyppejä!

Selaimesi ilmoittaa seuraavat mime-tyypit:
text/html
application/xhtml+xml
application/xml;q=0.9
*/*;q=0.8
<?php
$MimeTypes = $HTTP_SERVER_VARS['HTTP_ACCEPT'];

if (stristr($MimeTypes, "application/xhtml+xml") || stristr($MimeTypes, "text/html"))
{print "...";}

else {print "...";}

print "...";

$aMimeTypes = explode(",",$_SERVER['HTTP_ACCEPT']);

for($i=0;$i<count($aMimeTypes);$i++){
echo $aMimeTypes[$i] . "<br />";
?>

Testi meni riittävässä määrin läpi eräällä Opera ja eräällä Mozilla Gecko -selaimella, mutta ei MS IE 5.5:llä. Systeemi voisi toimia, jos kaikki WML-selaimet ilmoittavat tukevansa WML:ää ja ensin kysytään stristr($MimeTypes, "wml". Mikäli WML-selaimet eivät niin toimi, WML-selaimille pitäisi keksiä jokin muu tunnistuskeino.

phpfreaks: Mime Types.

Esittämäni moduloinnin vaihtoehtona on raskas XSLT-muunnos, jossa dokumentti luodaan ensin XML:nä ja muunnetaan joko WML 1.x tai XHTML dokumenteiksi.

Uudemmat kännykkäselaimet osaavat XHTML:ään perustuvaa WML 2.0:aa. Niille voi toteuttaa optimiratkaisun yksinkertaistetuilla XHTML-dokumenteilla. Tällaisten selainten täysi huomioiminen saattaa edellyttää erilaisia naviointi- ja Web-sivujen runko-osien rakennemoduuleja.

[Alku]