Luettelen alla aihealueittain tekemäni aihepiirit. Paluulinkkeinä tähän aihepiiriin on tämä valikko ja sivun yläreunassa oleva linkki Aihepiiriluettelo.
| |||||||||||||||
Tämä sivu on jaettu jaksoihin, jotka sisältävät seuraavia aiheita:
PHP:llä ei mielestäni kannata tuottaa kaikkea dokumentiin liittyviä seikkoja. CSS:llä kannattaa hallita dokumenttien esitysasullisia yksityiskohtia. CSS:n avulla voidaan myös jossakin määrin erottaa esitysasu ja sisältö toisistaan. Tavanomaisiin Web-dokumentteihin kuuluu kuitenkin aina varsinaiseen sisältöön kuulumattomia välttämättömiä rakenne-osia. Itse sisältöön eivät kuuluu myöskään perusnavigointielementit. Dokumentti voidaan kuitenkin jakaa katkelmiin (fragments), joista palvelin kasaa lopullisen dokumentin.
PHP on yksi palvelinpuolen mahdollinen kieli tämän toteuttamiseksi. PHP tunnettiin alunperin Rasmus Lerdorfin Personal Home Page Tools. PHP on HTML:n upotettu skriptikieli. Suuri osa syntaksista on lainattu C ja Perl kielistä lisättynä PHP-spesifisillä piirteillä. Päämääränä on kieli, joka antaa Web-kehittelijöille mahdollisuuden kirjoittaa nopeasti dynaamisia sivuja.
Alla on lista joistakin muiden kielten kanssa yhteisistä piirteistä, joiden tietäminen on välttämätöntä tämän sivun esimerkkien ymmärtämisen suhteen.:
PHP koodi erotetaan muusta sisällöstä yleensä <?php + ?> tai <? + ?> merkkauksilla (ainakin XML-dokumenteille pitäisi käyttää pidempää muotoa). Myös Microsoftin ASP (= Active Server Pages) tyylisiä merkkauksia (<% + %> ja <%= + %>) voi käyttää. Vaikka tiedostossa ei oli mitään muuta kuin PHP-koodia, PHP-koodi tulee ympäröidä PHP-merkkauksilla. PHP:tä voi käyttää kaikilla yleisillä palvelinohjelmistoilla.
Palvelimen tulee tunnistaa sivut, jotka käyttävät PHP:tä. Siksi lopullisen sivun tiedostopääte tulee olla tietynlainen. Yleensä palvelin on määritelty käsittelemään *.php, *.php3, *.php4 ja *.phml tiedostot PHP-jäsennintä tarvitsevina sivuina.
Palvelin- ja editorikohtaisia huomautuksia:
<style language="php">...</style> merkkauksia voi käytää, mutta ne voivat olla harmillisia editoitaessa koodia, sillä editori ei välttämättä tunnista niitä PHP-merkkauksiksi.Mikäli PHP:tä käyttävä tiedosto upotetaan sivuun, joka käyttää PHP:tä, upotettavan tiedoston tiedostopäätteen voi määrittää vapaasti. Tällaisia sivuja voitaisiin kutsua "orjadokumenteiksi", joita ei koskaan käytetä irrallisina vaan ainoastaan toisten dokumenttien osasina. Sivut, joita vierailijat näkevät internetissä olisivat tällöin "johtajasivuja". orjadokumenteille on yleisenä tapana antaa tiedostopääte inc (esim. includeTop.inc).
Kun käytetään palvelinpuolen skriptejä, niistäon sivujen latumisajoille sekä hyötyä että haittaa. Palvelinpuolen skriptien käyttö on hitaille tietokoneille etu, sillä palvelin suorittaa skriptit. Toisaalta nopealla koneella ja ruuhkaisella palvelimella skriptit voisivat toimia nopeammin selaimen suorittamana. Yleisesti ottaen palvelinpuolen skriptit ovat luotettavampia ja selainten väliset erot voi unohtaa.
Itselleni PHP on perustoiminnoiltaan ilmainen. Useille amatööreille PHP on ainoa mahdollisuus tehdä edullisesti suhteellisen dynaamisia sivuja. Mikäli haluaisin käyttää tietokantoja, siitä tulisi lisäkuluja. Olen omalla tietokoneellani hieman kokeillut tietokantojen käyttöä. Yritän soveltaa tietokantapohjaisen Web-suunnittelun perusideoita. En käsittele PHP:tä mitenkään perusteellisesti. Tämänkin sivun esimerkit saattavat tarvita perusteellisten PHP-oppaiden lukemista. Olen opetellut useimmat piirteet PHP Manual sivuista, jotka on editoinut Stig Sæther Bakken. Olen opetellut asioita myös hieman Rami Heinisuon PHP ja MySQL - Tietokantapohjaiset verkkopalvelut -kirjan avulla.
PHP: Download documentation; PHP ja MySQL - Tietokantapohjaiset verkkopalvelut (Rami Heinisuo).Katkelmat kootaan yhteen joko readfile(), require() tai include() funktioilla ja jokainen rivi päätetään puolipisteeseen (;). Haettava tiedosto on yleensä sulkumerkkien sisällä, mutta require kohdalla pelkät lainausmerkitkin (yksinkertaiset tai kaksinkertaiset) riittävät (esim. <?php require 'joku.inc';?>). Lisäksi on huomattava, että include() pitää lisäksi olla kaarisulkujen ({ + }) rajoittaman käskylohkon sisällä, mikäli se on ehtolauseen sisällä.
Niiden lisäksi tarvitaan perustulostuksissa joko print() tai echo() funktio, joka joko kirjoittaa uutta koodia tai kirjoittaa haetun koodin jonnekin toiseen paikkaan. Jälkimmäisessä tapauksessa haettu koodi on määritelty muuttujaksi. Alla on esim. muuttujan käyttämisestä tietyn merkkijonon tulostamiseksi:
<?php $Muuttuja="\"Tämä on muuttujan sisältämä teksti\"";
print $Muuttuja;?>
"Tämä on muuttujan sisältämä teksti"
Merkkijono voi sisältää tavallista tekstiä tai vaikka HTML-koodia. Mikäli merkkijonossa on yksin- tai kaksinkertaiset lainausmerkkejä, niiden eteen täytyy laittaa etukenoviiva (\) pakokirjaimeksi (escape character). Muutoin jäsennin tulkitsee lainausmerkkien joko päättävän muuttujan tai katkovan sitä osiin. Jos merkkijono jaettaisiin lainausmerkeillä osiin, välissä tulisi olla piste (esim. "jono"."jono"), jolloin kyseessä olisi konkatenointi.
Toisinaan tarvitaan ns. taulukkomuuttujia (arrays), joissa samalla muuttujalla on useita jäsenmuuttujia, esim.:
$aLinks = array('Linkki1.inc','Linkki2.inc','Linkki3.inc');
Funktioita, jotka sisällyttävät katkelmat toisiin dokumentteihin kannattaa käyttää siten, että palvelin toimisi mahdollisimman nopeasti, mutta funktioilla on myös omat ongelmansa. Alla hieman perustietoa:
Funktiota readfile() voi käyttää, jos katkelmassa jonka haetaan ei ole PHP-koodausta (jos tiedostossa olisi vahingossa PHP:tä, PHP-jäsennin ei jäsennä sitä PHP:nä). Esim. tiedosto topSection.inc
<div class="cNoPrint"><a href="#Top"><img src="../Kuvat/buttons/Top.gif" border="0" alt="[Alku]"
align="middle" title="Tämän sivun alkuun"/></a></div>
haetaan esim.:
<?php readfile('topSection.inc');?>
Funktiota require() voi käyttää, jos katkelmassa jonka haetaan on PHP-koodausta, mutta haettua tiedostoa ei tarvitse laittaa silmukkaan eikä haetuista tiedostoista luoda taulukkomuuttujaa. Esim. letters.inc tiedostossa olevan muuttuja
<?phphaetaan toisessa kohdin kirjoitettavaksi esim. seuraavalla koodilla:
$Standards="A";
...
?>
<?php require('letters.inc'); print $Standards;?>
Funktiota include() pitää käyttää, jos katkelmassa jonka haetaan on PHP-koodausta ja tiedostoa käytetään silmukoissa taulukkomuuttujan osina. Esim. tiedostoista Linkki1.inc, Linkki2.inc ja Linkki2.inc tehdään taulukkomuuttuja ja ne haetaan for-silmukkaan, jossa linkin ympärille kirjoitetaan listamerkkaukset. Linkkikokonaisuus tuotetaan listaelementin sisälle:
<ul>
<?php
$aLinks = array('Linkki1.inc','Linkki2.inc','Linkki3.inc');
for ($i = 0; $i < count($aLinks); $i++)
{
print "<li>";
include $aLinks[$i];
print "</li>";
}
?></ul>
Palvelimiin liittyviä huomautuksia:
Kaikki palvelimet eivät tue readfile() funktiota.
Jos require()-funktion kanssa tulee tilanne, että haettua sivua ei löydy, sivun käsittely pysähtyy virheeseen. Mikäli käytettäisiin include() funktiota palvelin pystyisi ohittamaan virheen. Funktion include() käyttö on siten kaikkein turvallisinta.
Palvelimet antavat vaihtelevassa määrin virheilmoituksia. Online-tilassa voi olla mahdotonta paikallistaa virhettä.
Tietyillä toimintamoodi- ja open_basedir-asetuksilla suhteelliset polut eivät toimi. Mikäli sivuja täytyy testata offline-tilassa, on syytä luoda hyvin systemaattinen nimeämiskäytäntö ja laittaa pääosa tiedostoista samaa hakemistoon. Kullekin tietotyypille tulee laittaa nimi, jota voi etsiä helposti tiedostomaskeja käyttäen (esim. *index.inc).
Palvelimet voivat estää myös absoluuttisten (http://...) polkujen käytön, jolloin PHP-tiedostoja ei voi jakaa useiden hakemiston kesken.
Ainakin seuraavat katkelmat olisivat mielekkäitä:
Sivun alkuosa eli suurin osan HEAD elementin sisään tulevaa
koodia.
Sivun yläosan rakennemerkkaukset.
Sivun yläosan navigointielementit.
Sivun asiasisältö.
Sivun loppuosan rakenne- ja navigointielementit + mahdolliset mainokset tai muut tiedotteet.
Itselläni esim. monijaksoisen liitesivun aloitussivun DynamicMenus.php3 rakenne on joskus ollut seuraava (olen lisännyt kommentteja):
<?php
/* Sivun yläosa: */
readfile('AdviceMeta.inc'); /* Alkuosa, jossa yhteiseen HEAD-osaan asti. */
require ('DynamicMenus0Top.inc'); /* Sivukohtainen HEAD-osa jaBODY-elementin alkumerkkaus.
/* BODY-osan alku: */
readfile('topSection.inc'); /* VälittömästiBODY-elementin jälkeen tuleva yhteinen BODY-osan koodaus. */
require ('dynamicMenusButtons.inc'); /* Sivukohtaiset navigointinappulat. */
readfile('AdviceOldInfo.inc'); /* Vanhoja selaimia koskeva yleinen tiedoite. */
/* BODY-osan yläosassa olevat yleiset navigointielementit: */
readfile('./include/AdviceHideInst.inc');
readfile('./include/allPages4.inc');
require ('AdviceNavigation.inc');
/* BODY-osan asiasisältöön liityvät osat: */
print "<div class=\"doc\" id=\"docSection\">"; /* Asiasisällön ympärille kirjoitettavan perusrakenne-elementin alkumerkkaus. Joillakin sivuilla tämä on osana varsinaista asiasisältöä. */
require ('./appendixesContents/DynamicMenus0Content.inc'); /* Sivun varsinainen asiasisältö. */
/* Sivun päättämiseen liityvät osat: */
readfile('./include/nextSection.inc'); /* Kaksi navigointinappia (linkki sivun alkuun ja seuraavalle sivulle). */
print "<br /></div>"; /* Asiasisällön ympärille kirjoitetun perusrakenne-elementin loppumerkkaus. */
readfile('bottomShort.inc'); /* Sivun lopullinen päätös, joka sisältääBODYjaHTMLelementtien päätösmerkkaukset. Joillakin sivuilla ennen päätösmerkkauksia on mainoksia ja tiedotteita. */
?>
Jotkin katkelmat voi ajatella ikään kuin moduuleiksi. Yllä olleessa tapauksissa kaikki selaimet saavat samat moduulit, mutta niitä voisi myös yksilöisi selainkohtaisesti (käsittelen selaintunnistuksia edempänä.
Sivukohtaisissa META elementeissä osa on yleistä ja osa sivukohtaista. Esim.
sivukuvauksen alkuun haen alisivuston yleisen kuvauksen ja loppuun kirjoitan sivukohtaisen tarkennuksen:
<meta name="description" content="<?php
readfile('metaContent.inc');?>..." />
Olen tehnyt PHP + JavaScript koodauksella hyvin tehokkaan tavan kontrolloida relatiivisia navigaatiolinkkejä (Takaisin, edelliselle sivulle, seuraavalle sivulle ja sivun alkuun; engl. up, prev ja next) laittamalla sivun HEAD-osaan (mallina on CSS-sivujen englanninkielinen versio):
<link rel="prev" href="javascript:prev();" />
<link rel="next" href="javascript:next();" />
<link rel="up" href="javascript:up();" />
...
<script language="JavaScript1.1" type="text/javascript">
<!--
function print $up{
open("index1.php3","_self");}
function prev(){
open("Linkkeja.php3","_self");}
function next(){
open("index2a.php3","_self");}
//--></script><style type="text/css">
...
Ja sivun BODY-osaan:
<body...>
...
<td align="left" style="width:16px !important">
<a href="javascript:prev();" onmouseover="window.status='The\ previous\ page\ or\ anchor';return true;" onmouseout="window.status='';return true;" class="left" title="The previous revious page tai anchor"><img
src="../Kuvat/buttons/Left.gif" border="0" alt="[Prev]" align=
"middle" style="height:16px; width:16px" /></a>
</td>
<td align="center" class="up">
<a href="javascript:up();" onmouseover="window.status='To\ the\ upper\ page\ level';return true;" onmouseout="window.status='';return true;" class="up" title="To the upper page level"><img
src="../Kuvat/buttons/TopSmallDouble.gif" border="0" alt="[Up]" align=
"middle" style="height:16px; width:16px" class="up" /></a></td>
<td align="right" style="width:16px !important">
<a href="javascript:next();" onmouseover="window.status='The\ next\ page\ or\ section';return true;" onmouseout="window.status='';return true;" title="the next page tai section" class="right"><img
src="../Kuvat/buttons/Right.gif" border="0" alt="[Next]" align="middle" style="height:16px; width:16px" /></a>
</td>
...
<?php readfile('./include/nextSection.inc'); ?>
</div>
</body>
</html>
Tiedostossa nextSection.inc on seuraava HTML-koodi:
<div style="margin-top:1.0em"><div class="cNoPrint"><a href="#Top"><img
src="../Kuvat/buttons/Top.gif" border="0" alt="[Top]" align="middle" title="To the top of this page"/></a><br /><br /></div>
<div class="noPrint noBig" align="right"><a href="javascript:up()"><img
src="../Kuvat/buttons/TopSmallDouble.gif" border="0" alt="[Up]" align="middle" title="To the upper page level" /></a> <a href="javascript:next();"><img
src="../Kuvat/buttons/Right.gif" border="0" alt="[Next]" align="right" title="The next page tai section" /></a></div><br /></div>
Kun käytetään JavaScript-koodausta ongelmana on se, että JavaScript-tuki täytyy olla päällä. Homma voitaisiin koodata pelkästään PHP:n avulla esim. seuraavalla tavalla (esimerkkinä siirtyminen sivulta Elementit0.php3 sivulle Elementit.php3):
<?php
$next = "Elementit.php3";
$up = ...
?>
LINK, PHP:llä laitetaan muuttujien avulla saadut attribuuttien arvot, esim. rel="up" href="<?php print $up;?>"<?php print "...<a href=\"".$next."\"><img src=\"../Kuvat/buttons/Right.gif\" border=\"0\" alt=\"[Next]\" align=\"right\" title=\"The next section\" /></a>"; ?>
tai
...<a href="<?php print $next;?>"><img src="../Kuvat/buttons/Right.gif" border="0" alt="[Next]" align="right" title="The next section" /></a>
Muuttujat voidaan sijoittaa myös funktioihin ja sitten kutsua niihin liittyviä funktioita, esim.:
<?php
function nextSection(){
$next=...
print $next; /* Muuttujat eivät toimi, jos ne määritellään funktion ulkopuolella paitsi siten, että funktion sisällä ilmoitetaan, että käytetään yleismuuttujia (esim.global $next, ...;). */
...
}
...<?php nextSection();?>
<a href="">...
Helpoiten selviää, jos muuttujille määrittelee oletusarvot, jotka sivukohtaisesti tarvittaessa määrittää uudelleen. Kaikissa tapauksissa osaa muuttujista ei tarvitse määritellä lainkaan sivukohtaisesti. Kun sivukohtaisia muuttujia käytetään, on muistettava, että muuttujat ottavan sen arvon, joka niille on viimeksi määritelty ennen muuttujiin liittyvää funktiota. Seuraava koodi ei toimi missään selaimessa:
<link rel="up" href="<?php up(); ?>" />
<?php
$up = "Content.php";
function print $up{
global $up;
print $up;
}
?>
Edellä olleessa esimerkissä linkit määritellään muuttujiksi. Käsittelen muuttujien käyttöä seuraavassa jaksossa hieman enemmän.
Muuttujien käytön perusidea on siinä, että muuttujat voidaan määritellä muualla kuin käyttökohteessaan. Tässä mielessä PHP-muuttujien käyttö muistuttaa class attribuutin käyttöä. Edellisessä jaksossa olevassa esimerkissä määrittelin niitä samalla sivulla, mikä muistuttaa STYLE elementin käyttöä.
Jos muuttujat määritellään johtajasivujen ulkopuolella, käyttö muistuttaa CSS:n @import at-säännön käyttöä, jossa tuontitiedosto on ikään kuin kirjoitettu kyseessä olevalle sivulle.
Koska tarvitaan sekä tavanomaisia muuttujia että taulukkomuuttujia eräs s-postiystäväni ehdotti, että taulukkomuuttujat ja muut muuttujatyypit kannattaisi nimetä seuraavaa käytäntöä noudattaen, jotta jatkossa heti näkisi minkä tyyppisestä muuttujasta on kyse:
Koska merkkijonomuuttuja on useimmin käytetty muuttujatyyppi, en laita sille mitään etuliitettä. Sekakirjasinten (engl. mixed case, leikillisesti camel case) eli "kamelikirjainten" käyttö puolestaan lisää nimien luettavuutta (suosittelen sekakirjasinten käyttöä alaviivan sijasta, esim. $aMinunTaulukkomuuttuja pikemmin kuin $a_minun_taulukkomuuttuja).
Kaikki tiedostokatkelmat voidaan kirjoittaa erillistiedostoihin, mutta pienet useaan kertaan käytettävät seikat kannattaa laittaa muuttujiksi. Jos sivut listaa aakkosilla, mutta ei ole varma, että sivujen keskinäinen järjestys tai sivumäärä säilyy samana, kannattaa luoda sivun järjestyskirjaimille merkkijonomuuttujat. Järjestyksen muuttuessa täytyy korjata paljon vähemmän sivuja. Muuttujaa voidaan käyttää samalla sivulla useaan otteeseen. Esim. dynaamisia valikoita käsittävän sivun aloitussivulla on samaa muuttujaa käytetty neljä kertaa:
Elementin META sisällä:
<meta name="description" content="... Lisäsivut <?php
include('letters.inc'); print $DynamicMenus;?>: ...
/>Elementin TITLE sisällä:
<title>... lisäsivut <?php include('letters.inc'); print
$DynamicMenus;?>...
</title>Taulukossa, jossa sivukohtaiset navigointinapit:
<div class="section">
<table summary="" class="section">
<tr>
<th class="page" title=""><?php include('letters.inc');
print $DynamicMenus;?></th>
<td><a href="DynamicMenus.php3" id="DMp1"><img
src="../Kuvat/buttons/i.gif" width="16" height="16" alt="[1]"
title="..." align="middle" border="0" /></a>
</td>
Dokumentin pääotsikon (H2) sisällä:
<h2><?php include('letters.inc'); print
$DynamicMenus;?>: ...</h2>Aiemmassa esimerkissä mainitsin sivukohtaisista muuttujista. Myös linkkilistat kannattaa luoda muuttujiksi. Linkit voi lajitella valmiiksi. Funktioilla sort() (ensimmäisestä viimeiseen) ja asort() (viimeisestä ensimmäiseen) aakkosten mukaan tapahtuva lajittelu tapahtuu muuttujan sisältämän merkkijonon eikä muuttujan nimen mukaan.
Jotta lajittelu menisi oikein olen laittanut linkeille class-attribuutti. Esim.
<?php
$CodeStyle ="<a class=\"CodeStyle\" href=\"http://www.codestyle.org/\" target=\"new\">CodeStyle</a>";
...
$aLinks = array($..., $..., $CodeStyle, $...);
sort($aLinks); /* Linkkihttp://www.codestyle.orgtulee nyt ensimmäiseksi. */
?>
<ul>
<?php
include('tutorials.inc');
for ($i = 0; $i < count($aLinks); $i++) /* Silmukan laskeminen aloitetaan nollasta, ja joka kierroksella lukemaa kasvatetaan yhdellä kunnes laskuri huomaa, että päästiin viimeisen muuttujan kohdalle. Taulukkomuuttujille on mahdollista käyttää myösforeachfunktioita, joka on taulukkomuuttujille tarkoitettu esimääritelty silmukointi. Se luo taulukkomuuttujista tavanomaisia muuttujia (esim.foreach($aLinks as $jokuMuuttuja)), jolloin laskuria ei tarvita. */
{
print ("<li>".$aLinks[$i]."</li>\n"); /* Jos käytettäisiinforeachfunktiota muuttujan nimenä oli annettu uusi muuttujanimi, esim.$jokuMuuttuja. Tässä tapauksessa on välttämätöntä käyttää kaksinkertaisia lainausmerkkejä. Jos käytetään "..." voidaan hakea muuttuja jonon keskelle siten, että muuttujan arvo tulostuu. Jos käytettäisiin '...' vain tarkat kirjaimet tulostuisivat, ei muuttujan arvo. Kohta voitaisiin toteuttaa myös ilman konkatenointioperaattoria muodossa("<li>$aLinks[$i]</li>\n"). */
}
?></ul>
Attribuutin id käyttö olisi loogisesti mielekkäämpää,
mutta käytön ongelmana on se, että samalla sivulla ei saisi koskaan olla kahta saman arvon
omaavaa id-attribuuttia. Saattaa olla olla tilanteita, joissa samaan linkkiin viitataan samalla sivulla
useaan otteeseen.
Jo en olisi käyttänyt luokka-attribuuttia, aakkostaminen olisi edellyttänyt erityisten avainten luomista. Olen kuitenkin pyrkinyt pitämään systeemin mahdollisimman yksinkertaisena. Alla on kuitenkin eräältä s-postiystävältä saadun mallin mukaan tehty esimerkki:
$aLinks = array(
"CodeStyle" => "<a href=\"http://www.codestyle.org/\" target=\"new\">CodeStyle</a>",
...
);
Esittämälläni tavalla voidaan saada luotua yksinkertaisia helposti hallittavia oikeita tietokantoja muistuttavia linkkitiedostoja. Listojen järjestely ja lopullinen tuottaminen muistuttavat tietokantatyöskentelyä. Edellä esitetyn ratkaisun ongelma on se, että linkkeihin liittyvät yksittäiset muuttujat täytyy manuaalisesti listata taulukkomuuttujiksi.
Mikäli linkkeihin liittyvät muuttujat listaa alla olevalla tavalla suoraan taulukkomuuttujiksi voidaan hakea joko koko taulukkomuuttuja tai sen yksittäisiä jäseniä. Taulukkomuuttujan päivittäminen ja uuden linkin lisääminen toteutuvat yhtä aikaa ilman, että taulukkomuuttujan päivittäminen aiheuttaa lisätöitä.
<?php
$aLinks = array(
($CodeStyle ="<a class=\"CodeStyle\" href=\"http://www.codestyle.org/\" target=\"new\">CodeStyle</a>"),
($IndexDOTCss="<a class=\"IndexDOTCss\" href=\"http://www.blooberry.com/indexdot/css/\" target=\"new\">Index DOT Css</a>"),
...
);
?>
Mikäli on tarpeen luoda uusi taulukkomuuttuja, jossa on enemmän muuttujia kuin jossakin olemassa olevassa taulukkomuuttujassa, uudet muuttuja voidaan lisätä olemassa olevaan taukkomuuttujaan, josta tulee uuden taulukkomuuttujan osa. Alla esimerkki array_push() funktion avulla luodusta uudesta taulukkomuuttujasta. Uudessa taulukkomuuttujassa on yksi jäsen enemmän kuin aikaisemmin luodussa taulukkomuuttujassa.
<?php
$aLinksFi = $aLinks;
array_push($aLinksFi,
($KeijoKortelainen="<a class=\"KeijoKort\" href=\"http://www.2kmediat.com/\" target=\"new\">Keijo Kortelainen, 2K mediat</a>")); /* Käytetty funktio lisää uuden muuttujan olemassa olevan taulukkomuuttujan loppuun. */
?>
Minun tapauksessani sama lopputulos olisi saatu funktiolla array_unshift(), joka lisää uuden muuttujan taulukkomuuttujan alkuun. Funktiolla array_merge() voidaan puolestaan yhdistää taulukkomuuttujia. Esimerkkitapauksessa muuttuja $KeijoKortelainen olisi ensin tarvinnut sijoittaa uuteen taulukkomuuttajaan.
Sillä että muuttujat määritellään taulukkomuuttujan sisällä on yksi haitta. Jos yksittäisiä muuttujia määritellään jossakin kohtaa uudelleen, muutos ei koske taulukkomuuttujia.
Jotta muuttujien uudet arvot saadaan myöskin taulukkomuuttujiin, taulukkomuuttujien sisällä olevat muuttujat täytyy poistaa ja niiden tilalle tulee laittaa muutetut muuttujat array_splice() funktion avulla, esim.:
$TopStyle=$TopStyle." (".$BradSoft.")";
$PageBuilder=$PageBuilder." (".$TafWS.")";
$DHTMLMenuB=$DHTMLMenuB." (".$xFX.")"; /* Alkuperäisessä$aApplicationstaulukkomuuttujassa edellä listatuilla muuttujilla on eri arvot. */
array_splice($aApplications,2,3,array($TopStyle,$PageBuilder,$DHTMLMenuB)); /* Parametrit2,3poistavat alkuperäiset muuttujat. */
Funktio array_splice() poistaa elementtejä alkuperäisestä taulukkomuuttujasta ns. siirtymän (offset) eli sijainnin ja pituuden (length) eli peräkkäisten muuttujien lukumäärän perusteella. Muuttujan nimen perusteella muuttien poistaminen ei ole mahdollista. Siksi alkupeäisten poistettavien muuttujien paikka täytyy tarkistaa ja poistettavien muuttujien tulee olla peräkkäin, jotta poisto ja uusien muuttujien antaminen voisi tapahtua yhdellä komennolla. Tämä on mielestäni suurin haittatekijä.
Oikeita tietokantoja käyttäen yksittäiset linkit voidaan hakea kenttien nimien perusteella. Koska muuttujien arvoja ei kirjoiteta suoraan taulukkomuuttijien sisään, paikalliset muutokset koskevat myös taulukkomuuttujia. Esittämässäni ratkaisussa uusien linkkien lisääminen linkkilistaan on kuitenkin suurin piirtein yhtä helppoa kuin tietokantoja käytettäessä. Alla on esimerkki tietokantojen käytöstä, jolla saavutettaisiin sama lopputulos kuin aikaisemmin esitetyssä esimerkissä noudetun inc-tiedoston käytöllä:
<ul>
<?php
result = mysql($conn, "SELECT class, osoite, nimi FROM tutorials"); /* Esimerkissä oletetaan, että tietokantataulukossa on kentätid,class,osoitenimijakuvaus, joista tässä esimerkissä noudetaan tietoa kolmesta kentästä. */
while (list($class, $osoite, $nimi) = mysql_fetch_row($result)) {
print("<li><a class=\"$class\" href=\"$osoite\" target=\"new\">$nimi</a></li>");
}
?>
</ul>
Olen tehnyt dynaamisia valikoita staattisesti. Niitä voidaan tuottaa myös PHP:n dynaamisesti. Verrattuna JavaScript-koodauksella tuotettuihin valikoihin etuna on se, että valikot ovat olemassa, vaikka JavaScript-tuki oli pois päältä.
Dynaamisten valikoiden alku ja loppu kannattaa joko laittaa tavanomaisena HTML-koodina haettavaan tiedostoon tai kirjoituttaa koodia funktioiden avulla. Funktiot eivät ole tässä kohdassa tarpeellisia.
Funktiota tarvitaan aina itse valikkokohtien kirjoittamiseen, jolloin valikkokohtien rakennetta voidaan myöhemmin muunnella. Valikkokohtien asiatieto tulee jakaa selkeästi määriteltäviin muuttujiin, esim. alla alivalikkokohdan tuottava funktio mItem():
function mItem(){
global $classD,$idD,$classD2,$classA,$idA,$title,$href,$mOver,$name;
print "<div class=\"".$classD."\" ".$idD." onmouseover=\"".$mOver."\"><div class=\"".$classD2."\"><a class=\"".$classA."\" id=\"".$idA."\" title=\"".$title."\" href=\"".$href."\">".$name."</a></div></div>";
}
Tässä koodissa on käytetty yksittäisiä yleismuuttujia. Muuttujia ei tarvitse laittaa argumenttilistaan sen paremmin funktiota määriteltäessä tai sitä kutsuttaessa. Kaikkia muuttujia ei tarvitse määritellä, mutta jos jonkin kohdan määrittelee, se koskee automaattisesti kaikkia jäljessä tulevia valikkokohtia mikäli samaa muuttujaa ei määritellä uudelleen. Funktiotiedoston loppuun voi laittaa joidenkin muuttujien oletusarvot ja funktio, jolla voi palauttaa oletusarvot, esim.:
$classD="noArrow";
$classD2="itemD";
$idD=""; /* Muuttujan arvo täytyy kirjoittaa muodossa$idD="id=\"idArvo"\";, sillä arvon tulee olla uniikki eikä tyhjä arvo kelpaa. Oletusarvoksi ei siten voi luoda tyhjää attribuuttia vaan oletusarvona on, että attribuuttia ei ole lainkaan. Muilla muuttujilla tuotetutid-attribuutit ovat sellaisia, että ne tuotetaan kaikille elementeille ja jokaisessa kohteessa täytyy antaa uniikki arvo. Tämä ongelma olisi vältettävissä käyttämällä lisäfunktiota (annan edempänä mallin sen toteuttamiseksi).*/
$classA="itemA";
$mOver="";
function setDefaults(){
global $classD,$idD,$classD2,$classA,$mOver;
$classD="noArrow";
$idD="";
$classD2="itemD";
$classA="itemA";
$mOver="";
}
Alla on esimerkki, jossa määritellään yksi alivalikkokohta. Koska esimerkissä on tavallisuudesta poikkeava luokkamääritys lopussa on oletusasetusten palautusfunktio:
$idA="uniikkiId"; $title="Jokin linkki"; $href="link1.php"; $classD2="jokinLuokka"; $name="Linkki 1"; smItem();setDefaults();
Tavallisesti määrittelen yhdeksästä muuttujien määrittelemistä arvosta neljä. Esimerkiksi
$idA="CSSCover"; $title="CSS-oppaan etusivu"; $href=" index1.php3"; $name="Aloitussivu"; mItem();tuottaa funktion mItem() kanssa seuraavan lopullisen lähdekoodin:
<div class="noArrow" ><div class="itemD"><a class="itemA" id="CSSCover"
title="CSS-oppaan etusivu" href="
index1.php3"
onmouseover="">CSS-oppaan etusivu</a></div></div>
Sen asemasta että muuttuja listataan ennen funktiokutsua, muuttujat voitaisiin määritellä myös funktiokutsun sisään pilkuilla toisistaan erotettuna (mItem($idA="CSSCover",...)).
Edellä olleen koodin ongelmana on se, että se luo paljon tyhjiä
onmouseover attribuutteja. Ne saa pois monimutkaisemmalla koodauksella, mikä ei
kuitenkaan ole mitenkään välttämätöntä. Em. attribuuttien ja
joidenkin id attribuuttien suhteen voisi tarkistaa, ovatko muuttujat tyhjiä. Jos ne olisivat
tyhjiä ei luotaisi attribuutteja lainkaan. Muussa tapauksessa tuotettaisiin attribuutti ja sen arvo. Alla koodi
tämän toteuttamiseksi:
checkIfEmpty(){
global $mOver,$idD;
if (empty($idD)){ } /* Funktion määrittely voi olla tyhjä. */
else {
print " id=\"".$idD."\"";
}
if (empty($mOver)){ }
else {
print " onmouseover=\"".$mOver."\"";
}
}
function mItem(){
...
print "<div class=\"".$classD."\"";
checkIfEmpty();
print "> class=\"".$classD2."...";
Yksittäisten muuttujien käyttäminen ei yhdessä suhteessa edusta yleisesti suositeltavaa ohjelmointitapaa. Muuttujien tiedot "vuotavat" yhdestä kohteesta seuraaviin kohteisiin. Yksittäisten muuttujien sijaan voitaisiin luoda yksi taulukkomuuttuja (esim. esim. $aItem) ja sille yksittäisiä tavanomaisia muuttujia vastaavat alimuuttujat seuraavaan tapaan:
function mItem(){
global $aItem;
... ".$aItem["classD"]." ... ".$aItem["href"]." ... ".$aItem["name"]"...
Alimuuttujien arvot voitaisiin määrittää seuraavalla tavalla => operaattoria käyttäen:
mItem($aItem = array("classD" => "noArrow", ..., "href" => " index1.php3", "name" => "Aloitussivu", ... ));
Nyt yksittäisten muuttujien arvot eivät vuoda, mutta ne täytyy aina määritellä taulukkomuuttujan sisällä uusiksi. On toki mahdollista, että tarkistetaan onko attribuutin arvo tyhjä (se on tyhjä, jos muuttujaa ei ole määritelty). Jos arvo havaitaan tyhjäksi, annetaan esimääritelty oletusarvo. Mielestäni järkevämpää on ei-tyhjille oletusarvoille oma taulukkomuuttuja, esim.:
$aItemDefaults = array("classD" => "noArrow", "classD2" => "itemD", "classA" => "itemA", "href" => "#");
Nämä oletusarvot voidaan yhdistetään funktion array_merge() avulla taulukkomuuttujan $aItem kanssa. Alla esimerkkitoteutus:
mItem(array_merge($aItemDefaults,$aItem = array(
"idD" => "GenericItem",
"idA" => "GenericA",
"classD" => $arrow,
"title" => "Yleistä",
"mOver" => "hideThlMenus(); MM_showHideLayers('indexPages','','hide','allSites','','hide','Generic','','show'...);"
)));
Jos arvot ovat erilaisia, jälkimmäisen yhdistetyn taulukkomuuttujat voittavat. Yllä olleessa tapauksessa "classD" => $arrow voittaa oletusasetuksen "classD" => "noArrow".
Koodia tarvitaan kaikissa edellä esittämissäni taulukkomuuttujien käyttötavoissa hieman enemmän kuin yksittäisiä muuttujia käytettäessä. Olen tosin nähnyt tiivistettyjä JavaScript taulukkomuuttujia, joissa yksittäiset arvot laitetaan pilkkujen väliin (esim. ,,,,noArrow,,,). Uskoisin, että myös PHP:n kanssa päästäisiin samankaltaiseen ratkaisuun. Ongelma on siinä, että on vaikea muista mikä arvo tulee kunkin pilkun väliin. Siksi en suosittelen niin tiiviin koodin käyttämistä. Mielestäni kaikista helpoin tapa ei-ammattilaisille on yksittäisten muuttujien käyttäminen. Monimutkaisten taulukkomuuttujien käyttö on ammattilaisia varten.
Alivalikoiden säilytinelementille kannattaa ainakin laittaa muuttuja, joka nimeää sen
yksilöllisesti id-attribuutin avulla. Alla olevassa esimerkkitapauksessa olen
käyttänyt yksittäisiä muuttujia (myös taulukkomuuttujia voitaisiin
käyttää):
function smTop(){
global $id,...;
print "<div id=\"".$id."\" class=\"pageGroup\"...
}
Siihen liittyvä funktiokutsu on esim.:
... $id = "MainPages"; ... smTop();
Näillä ratkaisuilla saadaan automaattisesti luotuja valikkokohtia, mutta valikkolohkon ja koko valikon luomisen suhteen automatisointi on vain osittaista.
Itselläni lähes kaikki ulkoasuun liittyvät seikat määritellään
ulkopuolisista CSS-tiedostoista käsin. Merkittävin poikkeus on se, että olen
määritellyt joidenkin elementtien korkeus määritellään PHP:n ja
style attribuuttien avulla. Valikon laatija määrittelee alivalikon sisällön
korkeuden muuttujan $iHeightMI (nimi tulee sanoista integer Height Menu Items =
kokonaisluku Korkeus Valikko Kohtien
). Tämä sisältökorkeus
määrittää varjojen korkeuden (korkeusarvot saattavat olla itselläni hieman
erilaisia):
function smTop(){
global ...,$iHeightMI;
print "<div id=\"".$id."\" class=\"pageGroup\" style=\"height:".($iHeightMI+10)."px;\">
...
}
function smBottom(){
global $iHeightMI;
print "</div><div class=\"shadowBase\" style=\"height:".($iHeightMI+122)."px;\"><div class=\"shadow\" style=\"height:".($iHeightMI+18)."px;\"> </div></div></div>";
}
Ratkaisuni heikkous on edelleen siinä, että sivujen laatijan täytyy käsin
määritell muuttujan $iHeightMI. Mikäli kukin alivalikko olisi yksi
taulukkomuuttuja, arvon voisi saada laskemalla kuinka monta valikkokohtaan kuuluu alivalikkoon ja kertomalla
tuo luku valikkokohdan korkeudella (joka itselläni on 15px). Ratkaisussani on monia
muitakin esitysasullisia piirteitä, jotka voisi automatisoida.
Kaikkien valikoiden asemoinnit määritellään tiedoston ../Css/dynamicMenus.css
alussa. Siinä määritellään myös yleiset esitysasulliset piirteet.
CSS:ää on helppo editoida siten, että saa joko pysty- tai vaakatasoisen
päävalikon.
Koska itselläni dynaamiset valikot toimivat myös staattisina linkkitaulukkoina, valikoiden sijoittuminen taulukkosoluihin ja taulukkoriveille täytyy määritellä ei-automaattisesti. Mikäli valikoita ei tarvita staattisina linkkitaulukkoina, kaikki valikkolohkoihin liittyvät rakenteet voidaan tuottaa PHP-funktioiden avulla.
Tein yhden valikon pohjatiedoston
, johon haetaan
funktioiden määrittelytiedosto
tekstitiedostona
. Jos et tarvitse
valikoiden ympärillä taulukkosoluja poista kaikki taulukkoelementteihin (TABLE,
TR ja TD) liittyvä lähdekoodi.
Käyttämällä CSS:ää ja PHP:tä valikoiden perusrakenne, ulkoasumäärittelyt, JavaScript-koodaus ja valikoiden sisältö voidaan lähes kokonaan erottaa toisistaan.
Jos ratkaisuani kehitettäisiin edelleen, se voitaisiin muuntaa tietokantapohjaiseksi, jolloin tuotettujen valikkokohtien attribuuttien arvot haetaan tiekannoista *.inc tiedostojen sijasta. Jos jokainen valikko on oma taulu, voidaan hakea koko taulun sisältö esim. while-silmukan ja list() avulla seuraavaan tapaan:
<?php
result = mysql($conn, "SELECT classD, idD, mOver,... FROM menutableMain");
while (list($idA, $name,...) = mysql_fetch_row($result)) {
print ...
}
?>
Erityiset väliotsikot ja tyhjät valikkokohdat on kuitenkin syytä unohtaa sillä ne keskeyttäisivät silmukat. tai ne tulisi rakentaa samalla kaavalla kuin linkilliset valikkokohdat.
On myös mahdollista luoda lomake, jonka avulla päivitys voi toteutua minkä tahansa Web-selaimen avulla. Lomakkeen jotkut kentät tulisi määritellä pakollisiksi ja jotkut valinnaisiksi. Näihin ortoni - ainakaan toistaiseksi - ei riitä. Ja vaikka minulla olisikin riittävät ordot, en kertoisi näillä sivuilla tietokantojen käyttöä.
Jos dynaamiset valikot tuntuvat latautuvan verkossa liian hitaasti, valikon voi koota valmiiksi kun tekee jonkin *.php -tiedoston, johon hakee valikon tarvitsemat osat. Kasattu valikkotiedosto tulee tallentaa alkuperäisellä nimellä johonkin toiseen hakemistoon, josta sen voi lähettää verkkoon.
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:
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
<?phppitäisi tulostaa selaimesi tunnistusmerkkijonon, joka näkyy tämän tekstin alapuolella:
global $userBrowser;
$userBrowser = $_SERVER['HTTP_USER_AGENT'];
print $userBrowser;
?>
CCBot/1.0 (+http://www.commoncrawl.org/bot.html)
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")); /* Funktionstristr()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äinensubstr()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:
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.
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:
<?php
include('...'); /* Tiedosto sisältää muuttujamääritykset. */
if ($NN4){echo "<!--\n";}?>
<link rel="stylesheet" ...
...
<?php if ($NN4){echo "-->\n";}?>
ja siihen liittyvät muuttujamäärittelyt
).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
):
HEAD-elementti.META-elementti (tuetut attribuutit ovat osittain eri).P ja PRE (jälkimmäinen vain WML 1.2:ssä).EM).A.IMG (kuvaformaatti on eri, joten tarvitaan skripti, joka valitsee eri kuvat).BR).FIELDSET, INPUT, SELECT, OPTGROUP ja OPTION.Mikäli WML-selaimia tuetaan ainakin seuraavat asiat tulee ottaa huomioon:
. Esim. HTML
4.0 tason koodaus riitä. Mielekäs peruskoodaus on XHTML
1.0, jossa ei käytetä aivan kaikkia XHTML:n piirteitä.card elementeillä jaksoihin eikä kokoavaa
runko-osan elementtiä ole lainkaan). On välttämättä
luotava käyttöympäristöriippuvaisia runko-osan aloituksia
ja dokumentin päätöksiä.id-attribuutit (jos rinnalla on name attribuutti,
arvojen tulee olla identtisiä esim. <a name="anchor1" id="anchor1">).BLOCKQUOTE) ja kaikissa
muissa lohkoissa, joissa tekstin tulee välttämättä olla
eri rivillä, sisältö kappaleiksi (esim. <li><p>...
</p></li>). Vaikka WML 1.x tukeva selain ei sisennäkään
tekstiä oikein, teksti ei kuitenkaan jää lukukelvottamaksi. 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
text/xml;q=0.9
text/plain;q=0.8
image/png
*/*;q=0.5
<?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.
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.
Jotta dokumenttien luominen olisi mahdollisimman dynaamista PHP:tä ja CSS:ää käyttäen useille käyttöympäristöille, suosittelen laatimaan sivut seuraavia periaatteita käyttäen:
class-attribuutteja, että voit jälkikäteen helposti muuttaa dokumenttien ulkoasua.FONT) ja attribuuttien käyttöä - ne kasvattavat turhaan tiedostokokoja.