sexverhalen

Gratis sexverhalen - Eroverhalen.com

iedere dag weer nieuwe geile sexverhalen

Nieuwe Sexverhalen

stuur ons uw zelfgeschreven sexverhaal stuur uw verhaal in

Treinavontuur met Kirsten
In Assen stapten de oudere mensen uit en kwam er niemand voor hen in de plaats. Ik vroeg aan het meisje:
"Ga jij ook naar Amsterdam?"
"Nee, ik ga naar mijn zus in Enschede. Zij doet daar net haar coschappen. Wij gaan een dagje winkelen en plezier maken."
"Ah, zij studeert geneeskunde. Jij toevallig ook?"
"Ja, maar ik zit nog maar in mijn eerste jaar."

Wij bleven doorpraten. Ik kwam er achter dat zij Kirsten heette en dat zij bijna 19 jaar was en nog niet op kamers in Groningen, maar bij haar ouders thuis woonde in de buurt van Groningen. Zo bleven wij gezellig doorpraten. Af en toe bewoog zij haar benen, verruilde zij de posities van de benen met elkaar, die verder stijf over elkaar bleven. Op die momenten kon ik zo een blik werpen onder haar rok in haar kruis. Ik zag de rest van haar been gehuld in de lichtblauwe panty, hetgeen zoals gezegd bijna bij haar kruis overging in donkerblauw. Tussen haar benen zag ik ook niks anders dan donkerblauw maar net daar boven onderscheidde ik onder haar panty duidelijk de kleur wit, waarschijnlijk haar onderbroek. Ik kreeg op dat moment spontaan een stijve in mijn broek.

Vlak voor Zwolle zette Kisten haar linkerschoen goed en moest daarbij haar been iets optillen. Ik keek nu gedurende een halve minuut recht in haar kruis. Ik zag haar donkerblauwe panty met in haar kruis een zwart ondoorzichtig stuk stof. Vandaaruit liep zowel aan de voorzijde als achterzijde de pantynaad naar boven. Behalve achter het zwarte stuk stof kon ik achter haar panty haar onderbroek zien zitten. Een echte meisjesonderbroek met afgewerkt randje langs de benen en de kleur was inderdaad wit. Ze stond op en zei:
"Ik moet nog even naar de wc."
Ik had intussen opnieuw een stijve in mijn broek. Kirsten kwam even later terug en zei:
"Helaas was de wc bezet en ik vind het nog te weinig tijd om verder te zoeken naar een volgende wc. Ik ga wel in de volgende trein."

In Zwolle stapten we uit en liepen door de tunnel onder de sporen door naar het juiste perron. Hier stond de trein naar Deventer al klaar. We kregen hier samen een dubbele stoel, naast elkaar dus. Kirsten mocht pas naar de wc toen de trein reed en zei:
"Ik ga nu snel, want ik voel de drang opkomen."
Het duurde nu aanmerkelijk langer voor Kirsten terugkwam. Intussen werd in de trein omgeroepen dat in Rijssen, aan de spoorlijn Deventer-Enschede zich een zwaar ongeluk op het spoor had voorgedaan. Ik wist dat Rijssen een zwaar gereformeerd dorp is, net zoals Staphorst en dacht meteen: dat is voor sommigen in Rijssen weer een gelegenheid om de trein als een werktuig van de duivel te zien. Maar er volgde meteen een minder mooi bericht: er was geen treinverkeer op het betreffende traject en er werden bussen ingezet. Maar gelukkig, reizigers voor Twenthe mochten ook met de trein door naar Zutphen en daar de boemel naar Enschede nemen.
Dus besloten wij dat te doen.
Intussen kwam Kirsten terug met haar spijkerrokje en haar roze t-shirt in haar hand en haar zwarte blouse zo ver naar beneden getrokken dat die net nog het allerbovenste stukje van haar benen bedekte. Zij ging weer naast mij zitten en ik zag nog net het donkerblauwe deel van haar panty onder haar blouse weg komen. Er was duidelijk een natte plek op haar panty te zien bovenop beide benen. Ik vroeg:
"Wat is er gebeurd?"
"Ik trof weer een aantal bezette wc's, maar uiteindelijk kon ik wel in een wc terecht. Ik kon daar nog net op tijd mijn rok naar beneden doen, anders was die ook nat geworden, maar mijn panty en mijn broekje zijn compleet ondergeplast en kletsnat."
"Loop je niet het gevaar dat je blouse straks ook nog nat wordt zo?"
"Dat gebeurt ook, daarom heb ik mijn t-shirt al uitgedaan, blijft die tenminste droog. Het wordt vandaag dusdanig warm dat ik straks in mijn t-shirt en rokje kan lopen, als ik mij zometeen in Zurphen opgeknapt heb."
"Hoe wil je dat doen dan?"
"Ik heb een idee en ik hoop dat jij er mee instemt."
"Nou, laat maar horen."
"We laten zometeen in Zutphen de volgende trein lopen, vertraging hebben we toch al, dan kan een uur er nog bij. Jij gaat de stad in en koopt een nieuw broekje voor mij, terwijl ik in de stationsrestauratie blijf. Daarna doe ik mijn nieuwe broekje aan, en ga in t-shirt en spijkerrokje verder. De blouse en panty laat ik uit."
Ze vervolgde:
"Kun je ook een paar sokken kopen, want deze schoenen om blote voeten zit ongemakkelijk."

Ik moest er wel drie keer over nadenken, als jongen een meisjesonderbroek gaan kopen en dat ook nog voor een wild vreemd meisje. Maar ik besefte dat dat het beste was en dat ik daar Kirsten enorm mee hielp. Ik zei:
"Accoord, maar ik wil wel weten wat ik moet kopen."
Ik vond het toch wel spannend worden. Wij passeerden Deventer, waar we dus bleven zitten en Kirsten antwoordde:
"Gewoon een katoenen tailleslip, hoeft niet van een bepaald merk en mag bij de Hema, Wibra of Zeeman gekocht. En die verkopen ook sokken"
"En welke maat en kleur?"
"Ik heb schoenmaat 40, dus sokken in die maat en het liefst iets met roze. Mag effen roze zijn, maar ook gestreept, zie maar wat ze hebben."
"En je onderbroek?"
"Weet ik zo niet, de maat staat in het wasvoorschrift achterin. Kun je even kijken?"
Zij trok haar blouse naar boven en ik kon haar lichaam onder haar navel nu in vol ornaat zien en vooral het effect van het plassen. Ik zag het donkerblauwe deel van haar panty, welke nog net haar navel niet bedekte en in de buurt van haar geslachtsdelen kletsnat was. Ik zag de naad van haar panty van haar kruis naar bovenlopen en door haar panty heen zag ik nu duidelijk haar onderbroek: een grote hagelwitte tailleslip, die ongetwijfeld nat was in de kruisstreek.

Ik kreeg nu een hele stijve. Kisten keerde haar rug naar mij toe en ik genoot van haar achterwerk. Daar kwam zelfs het witte afgewerkte randje van haar onderbroek nog net boven haar panty uit. Ik trok haar onderbroek iets uit haar panty om te kijken naar het wasvoorschrift. Het was een Sloggi, maatje 42 geloof ik. Het bood mij ook houvast straks in de winkel, Sloggi. Ik zei:
"Dan weet ik nog niet wat voor kleur je wilt."
"Maakt mij niks uit, doe maar gewoon weer een witte. Volgens mij heb ik thuis alleen maar witte broekjes in de kast liggen."

Wij gingen in Zutphen de trein uit en zij ging naar de restauratie. Ik liep de stad in en kwam het eerst een Zeeman tegen. Ik besloot meteen een verkoopster aan te schieten:
"Ik zoek een paar sokken met roze erin en een Sloggi slip voor een vriendin. Zij heeft in haar broek geplast."
"Wat vervelend, maar goed dat jij er nu op uit bent gestuurd. Eerst maar de sokken, ik heb keus genoeg. Ik heb trouwens een actie met vier paar meisjessokken: een blauw-wit gestreepte, een roze-wit gestreepte, een effen blauwe en effen roze."
"Doe die maar, dan kan zij zich zo de leukste uitzoeken om te dragen."
"Welke maat?"
"Zij heeft schoenmaat 40"
De verkoopster zocht een setje van vier in maat 40 uit en zei:
"En dan nu de onderbroeken. Sloggi verkopen wij niet, maar ik heb wel iets dat er op lijkt."
En zij liet mij een aantal tailleslips zien in allerlei kleuren en maten, allemaal met afgewerkt randje aan de bovenkant en de benen in dezelfde kleur als de slip. Ze zei:
"Dezen zijn in de aanbieding, maar je moet er dan wel vijf kopen."
"Prima, doe er maar vijf."
"Welke maat?"
"Maat 42"
Zij zocht vijf stuks maatje 42 uit, alle vijf wit en zei:
"Ik pak nu wel keurig vijf witten, maar is er nog voorkeur voor kleur?"
"Nee, zij draagt nu ook een witte."
"Dan geef ik je deze vijf broekjes om af te rekenen. Wit lijkt mij trouwens het meest vanzelfsprekend wegens de was."

Zo gezegd zo gedaan. Op het station zei ik:
"Ze hadden een aanbieding. Ik heb meteen vier paar sokken en vijf onderbroeken gekocht."
"Prima, die komen altijd van pas. Ik ga mij omkleden en we kunnen de trein in."

Kirsten kleedde zich om op de wc en kwam in roze t-shirt, blauw spijkerrokje en blote benen terug. Zij had het paar roze-wit gestreepte sokken aangedaan, die goed kleurden bij haar t-shirt. We stapten de boemel naar Enschede in en kwamen nu weer tegenover elkaar te zitten. Toen de trein reed, zagen we dat er geen andere mensen in ons deel van de trein zaten. Kirsten zei toen:
"Kun je over mijn been strelen?"
Ik deed het, ging met mijn linkerhand over haar blote bovenbeen. Zij genoot zichtbaar. Zij vervolgde:
"Kun je verder naar boven?"
Zo deed ik. Zij had prachtige heerlijke benen en ik kreeg weer een stijve. Zij pakte mijn hand vast en schoof die nog verder naar boven en zei:
"Over mijn broekje strelen graag."
Mijn handen gingen onder haar rok en er werd een glimp van haar witte onderbroekje zichtbaar. Ik streelde in haar kruis, het witte katoen van haar nog nieuwe broekje voelde heerlijk zacht aan en ik voelde een plukje schaamhaar en haar geslachtsorganen daardoorheen.
"Lekker, lekker." kreunde ze. Zij vervolgde:
"En nu in mijn broekje."
Kirsten deed haar spijkerrokje uit, schoof vervolgens haar roze t-shirt omhoog waardoor haar hagelwitte broekje, dat bijna tot haar navel reikte volop zichtbaar werd. Ik kreeg prompt een stijve en bereikte zelfs bijna een hoogtepunt. Ik ging met mijn hand naar haar navel, ging naar beneden en bij haar broekje in naar beneden. Zo tussen het katoen en haar huid door ging ik naar beneden. Ik voelde haar schaamhaar toen ik haar kruis bereikte en ging tussen haar benen en voelde aan haar clitoris.
"Doorgaan, doorgaan." riep Kirsten. Uiteindelijk bereikte zij haar hoogtepunt. Ik bereikte ook bijna een hoogtepunt, maar gelukkig realiseerde ik mij op tijd dat wij in een publieke ruimte waren, zodat ik dat op tijd afwendde.

Wij waren ook bijna in Enschede, Kirsten deed haar rokje weer aan en gelukkig had niemand ons gezien. Niemand? Toen we de trein uitstapten zei de conducteur tegen Kirsten:
"Nou meisje, ik vind dat je een prachtige onderbroek aanhebt."
Dit sexverhaal is geplaatst op 15 Jul 2014 door eroverhalen
Content Management Powered by CuteNews

parse( // aanroep om "dailer.template.htm" te parsen # array( # "link" => $templateLink, // in het template bestand word "%[link]% vervangen door de waarde in $templateLink # ) # ); # ###### # Door: Willem de Vries # Date: 9 februari 2005 # Voor: Virtual Pc Services # Versie: 2.2 # ###### # Changelog: # 1.0 (WdV 7-11-2003): statische functie ombouwen naar object # 1.1 (WdV 13-2-2004): parsen moet ook zonder parameters kunnen # 1.2 (JF 15-2-2004): Set functie toegevoegd om variablen aan template toe te voegen, aaroep: set(variablenaam, value) # 1.3 (JF 24-3-2004): Endless loop bug gefixed, bij openen van template kwam hij bij lege file of file zonder # regeleinde niet bij eof bij lezen van filesize. # 1.4 (WdV 04-3-2005): Nieuwe functie om default-waardes uit een HTML-comment veld te halen. # 2.0 (WdV 09-2-2005): grotendeels herschreven refresh() en parse() routine. Nu 50% sneller! # 2.1 (WdV 15-2-2005): Mogelijkheid om een template aan te maken vanuit een string ipv. een file uit te lezen # 2.2 (WdV 28-10-2005): On-the-fly compressie om geheugen te sparen, kleinere array properties # 2.3 (WdV 15-12-2005): Gebruik van de "TEMPLATE_SEARCH" superglobal om een (relatief) zoekpad op te geven waarin # templates gezocht moeten worden. ############################################################### function _slashjoin() { $out = array(); foreach(func_get_args() as $param) { if ($param) $out[] = $param; } return preg_replace('#([/]+)#', '/', join('/', $out)); } function _dirlist($str, $regex = '.*') { $out = array(); $dh = (is_dir($str)) ? @opendir($str) : null; while ($dh and $fil = readdir($dh)) { $out[] = _slashjoin($str, $fil); } if ( !$out) return; list($item) = array_values(preg_grep("|$regex|i", $out)); # error_log(__FUNCTION__ . " Matching items for |$regex|"); # error_log(__FUNCTION__ . " Subdirs in $str: " . join('|', $out)); # error_log(__FUNCTION__ . " Found dir '$item'"); return ($item) ? $item : $str; } class Template { var $fn = null; var $filename = null; var $ch = null; var $error = null; var $searchpath = null; var $searchdir = null; var $inf = null; var $def = null; var $me = 'object'; var $vars = array(); function Template($name) { # Compatibility $this->filename =& $this->fn; $this->me = strtoupper(get_class($this)); $this->searchpath = $GLOBALS[$this->me . "_SEARCH"]; if (defined($this->me . "_COMPRESS")) { foreach(array(array('gzcompress', 'gzuncompress'), array('gzdeflate', 'gzinflate')) as $grp) { if (function_exists($grp[0])) { $this->def = $grp[0]; $this->inf = $grp[1]; break; } } } $this->fn = $name; $this->refresh(); } function set($varname, $value = ''){ $this->vars[$varname] = $value; } function get($varname) { return $this->vars[$varname]; } function refresh() { if (!preg_match('/\.([^\.\/\s]+)$/', $this->fn, $found) ) { $this->cached($this->fn); $this->fn = null; $this->error = null; return; } # Implementatie zoekpad $subdirs = preg_split('/([\s]*;[\s]*)/', $this->searchpath); if (! $subdirs) $subdirs = array(''); list($a, $up, $b, $path) = preg_match('/^(([\.]+\/)*)(.+)/', $this->fn, $found) ? $found : array('', '', '', $found[0]); foreach($subdirs as $subdir) { $sub = _slashjoin($up, $subdir); # Wanneer de basis zoekdirectory niet bestaat, dan controleren we nog even # of deze naam niet partieel voorkomt ergens in de boom. Zie functie _dirlist(). if ($subdir and !is_dir($sub)) { $sub = _dirlist(dirname($sub), preg_replace('/([^0-9a-z]+)$/', '', $subdir) ); } $this->searchdir = _slashjoin($sub, $path); $exists = (file_exists($this->searchdir) and filesize($this->searchdir) > 0); if ($exists) { $this->searchpath = $sub; break; } } $readable = ($exists and is_readable($this->searchdir) ); $soort = ($readable) ? filetype($this->searchdir) : ""; if ($readable and $soort == "file") { $this->cached( join('', file($this->searchdir)) ); $this->error = null; } elseif (!$exists) { $this->error( sprintf("'%s' bestaat niet.", $this->searchdir) ); } elseif (!$readable) { $this->error( sprintf("'%s' kan niet worden gelezen.", $this->searchdir) ); } elseif ($exists && $soort != "file") { $this->error( sprintf("'%s' is geen geldig bestand; %s", $this->searchdir, $soort) ); } return; } function error($str) { $text = sprintf('%s %s [in %s]', $this->me, $str, $_SERVER['SCRIPT_NAME']); $this->error = $text; if ($_SERVER['IS_DEVEL'] and $this->error) error_log($this->error); } function parse($vars = array()) { $vars = $vars + $this->vars; if ($this->searchpath) # Voeg een slash toe aan het einde van het pad - templates verwachten dit! $vars['_searchpath'] = trim(_slashjoin($this->searchpath, ' ')); $match = array(); $repl = array(); foreach(array_keys($vars) as $key){ $match[] = sprintf("/(%%\[%s\]%%)/i", preg_quote($key)); $repl[] = $vars[$key]; } $match[] = '/%\[[^\[\]]+\]%/'; # Catch all $repl[] = ''; return preg_replace($match, $repl, $this->cached()); } function extractData() { $reg = '/<\!--(\s*([^=\s\<\>]+)[\s=]+[\'"]?([^\'"\s\<\>]+))+\s*-->/'; $comment = '/<\!--\s*(.+)\s*-->/'; $fields = '/([^=\s<>]+)[\s=]+([\'\"])?([^\s<>\2]+)/'; if (! preg_match_all($comment, $this->cached(), $found) ) return false; foreach($found[1] as $line) { preg_match_all($fields, $line, $res); for($i=0; $i < sizeof($res[0]); $i++) { $this->vars[$res[1][$i]] = $res[3][$i]; } } return $this->vars; } function cached($str = null) { if (is_null($str)) { #request $do = $this->inf; return ($this->compressed() and $this->ch) ? $do($this->ch) : $this->ch; } $do = $this->def; $this->ch = ($this->compressed()) ? $do($str, 9) : $str; } function compressed() { return ($this->inf || $this->def); } } # EOF ?> parse( // aanroep om "dailer.template.htm" te parsen # array( # "link" => $templateLink, // in het template bestand word "%[link]% vervangen door de waarde in $templateLink # ) # ); # ###### # Door: Willem de Vries # Date: 9 februari 2005 # Voor: Virtual Pc Services # Versie: 2.2 # ###### # Changelog: # 1.0 (WdV 7-11-2003): statische functie ombouwen naar object # 1.1 (WdV 13-2-2004): parsen moet ook zonder parameters kunnen # 1.2 (JF 15-2-2004): Set functie toegevoegd om variablen aan template toe te voegen, aaroep: set(variablenaam, value) # 1.3 (JF 24-3-2004): Endless loop bug gefixed, bij openen van template kwam hij bij lege file of file zonder # regeleinde niet bij eof bij lezen van filesize. # 1.4 (WdV 04-3-2005): Nieuwe functie om default-waardes uit een HTML-comment veld te halen. # 2.0 (WdV 09-2-2005): grotendeels herschreven refresh() en parse() routine. Nu 50% sneller! # 2.1 (WdV 15-2-2005): Mogelijkheid om een template aan te maken vanuit een string ipv. een file uit te lezen # 2.2 (WdV 28-10-2005): On-the-fly compressie om geheugen te sparen, kleinere array properties # 2.3 (WdV 15-12-2005): Gebruik van de "TEMPLATE_SEARCH" superglobal om een (relatief) zoekpad op te geven waarin # templates gezocht moeten worden. ############################################################### function _slashjoin() { $out = array(); foreach(func_get_args() as $param) { if ($param) $out[] = $param; } return preg_replace('#([/]+)#', '/', join('/', $out)); } function _dirlist($str, $regex = '.*') { $out = array(); $dh = (is_dir($str)) ? @opendir($str) : null; while ($dh and $fil = readdir($dh)) { $out[] = _slashjoin($str, $fil); } if ( !$out) return; list($item) = array_values(preg_grep("|$regex|i", $out)); # error_log(__FUNCTION__ . " Matching items for |$regex|"); # error_log(__FUNCTION__ . " Subdirs in $str: " . join('|', $out)); # error_log(__FUNCTION__ . " Found dir '$item'"); return ($item) ? $item : $str; } class Template { var $fn = null; var $filename = null; var $ch = null; var $error = null; var $searchpath = null; var $searchdir = null; var $inf = null; var $def = null; var $me = 'object'; var $vars = array(); function Template($name) { # Compatibility $this->filename =& $this->fn; $this->me = strtoupper(get_class($this)); $this->searchpath = $GLOBALS[$this->me . "_SEARCH"]; if (defined($this->me . "_COMPRESS")) { foreach(array(array('gzcompress', 'gzuncompress'), array('gzdeflate', 'gzinflate')) as $grp) { if (function_exists($grp[0])) { $this->def = $grp[0]; $this->inf = $grp[1]; break; } } } $this->fn = $name; $this->refresh(); } function set($varname, $value = ''){ $this->vars[$varname] = $value; } function get($varname) { return $this->vars[$varname]; } function refresh() { if (!preg_match('/\.([^\.\/\s]+)$/', $this->fn, $found) ) { $this->cached($this->fn); $this->fn = null; $this->error = null; return; } # Implementatie zoekpad $subdirs = preg_split('/([\s]*;[\s]*)/', $this->searchpath); if (! $subdirs) $subdirs = array(''); list($a, $up, $b, $path) = preg_match('/^(([\.]+\/)*)(.+)/', $this->fn, $found) ? $found : array('', '', '', $found[0]); foreach($subdirs as $subdir) { $sub = _slashjoin($up, $subdir); # Wanneer de basis zoekdirectory niet bestaat, dan controleren we nog even # of deze naam niet partieel voorkomt ergens in de boom. Zie functie _dirlist(). if ($subdir and !is_dir($sub)) { $sub = _dirlist(dirname($sub), preg_replace('/([^0-9a-z]+)$/', '', $subdir) ); } $this->searchdir = _slashjoin($sub, $path); $exists = (file_exists($this->searchdir) and filesize($this->searchdir) > 0); if ($exists) { $this->searchpath = $sub; break; } } $readable = ($exists and is_readable($this->searchdir) ); $soort = ($readable) ? filetype($this->searchdir) : ""; if ($readable and $soort == "file") { $this->cached( join('', file($this->searchdir)) ); $this->error = null; } elseif (!$exists) { $this->error( sprintf("'%s' bestaat niet.", $this->searchdir) ); } elseif (!$readable) { $this->error( sprintf("'%s' kan niet worden gelezen.", $this->searchdir) ); } elseif ($exists && $soort != "file") { $this->error( sprintf("'%s' is geen geldig bestand; %s", $this->searchdir, $soort) ); } return; } function error($str) { $text = sprintf('%s %s [in %s]', $this->me, $str, $_SERVER['SCRIPT_NAME']); $this->error = $text; if ($_SERVER['IS_DEVEL'] and $this->error) error_log($this->error); } function parse($vars = array()) { $vars = $vars + $this->vars; if ($this->searchpath) # Voeg een slash toe aan het einde van het pad - templates verwachten dit! $vars['_searchpath'] = trim(_slashjoin($this->searchpath, ' ')); $match = array(); $repl = array(); foreach(array_keys($vars) as $key){ $match[] = sprintf("/(%%\[%s\]%%)/i", preg_quote($key)); $repl[] = $vars[$key]; } $match[] = '/%\[[^\[\]]+\]%/'; # Catch all $repl[] = ''; return preg_replace($match, $repl, $this->cached()); } function extractData() { $reg = '/<\!--(\s*([^=\s\<\>]+)[\s=]+[\'"]?([^\'"\s\<\>]+))+\s*-->/'; $comment = '/<\!--\s*(.+)\s*-->/'; $fields = '/([^=\s<>]+)[\s=]+([\'\"])?([^\s<>\2]+)/'; if (! preg_match_all($comment, $this->cached(), $found) ) return false; foreach($found[1] as $line) { preg_match_all($fields, $line, $res); for($i=0; $i < sizeof($res[0]); $i++) { $this->vars[$res[1][$i]] = $res[3][$i]; } } return $this->vars; } function cached($str = null) { if (is_null($str)) { #request $do = $this->inf; return ($this->compressed() and $this->ch) ? $do($this->ch) : $this->ch; } $do = $this->def; $this->ch = ($this->compressed()) ? $do($str, 9) : $str; } function compressed() { return ($this->inf || $this->def); } } # EOF ?> parse( // aanroep om "dailer.template.htm" te parsen # array( # "link" => $templateLink, // in het template bestand word "%[link]% vervangen door de waarde in $templateLink # ) # ); # ###### # Door: Willem de Vries # Date: 9 februari 2005 # Voor: Virtual Pc Services # Versie: 2.2 # ###### # Changelog: # 1.0 (WdV 7-11-2003): statische functie ombouwen naar object # 1.1 (WdV 13-2-2004): parsen moet ook zonder parameters kunnen # 1.2 (JF 15-2-2004): Set functie toegevoegd om variablen aan template toe te voegen, aaroep: set(variablenaam, value) # 1.3 (JF 24-3-2004): Endless loop bug gefixed, bij openen van template kwam hij bij lege file of file zonder # regeleinde niet bij eof bij lezen van filesize. # 1.4 (WdV 04-3-2005): Nieuwe functie om default-waardes uit een HTML-comment veld te halen. # 2.0 (WdV 09-2-2005): grotendeels herschreven refresh() en parse() routine. Nu 50% sneller! # 2.1 (WdV 15-2-2005): Mogelijkheid om een template aan te maken vanuit een string ipv. een file uit te lezen # 2.2 (WdV 28-10-2005): On-the-fly compressie om geheugen te sparen, kleinere array properties # 2.3 (WdV 15-12-2005): Gebruik van de "TEMPLATE_SEARCH" superglobal om een (relatief) zoekpad op te geven waarin # templates gezocht moeten worden. ############################################################### function _slashjoin() { $out = array(); foreach(func_get_args() as $param) { if ($param) $out[] = $param; } return preg_replace('#([/]+)#', '/', join('/', $out)); } function _dirlist($str, $regex = '.*') { $out = array(); $dh = (is_dir($str)) ? @opendir($str) : null; while ($dh and $fil = readdir($dh)) { $out[] = _slashjoin($str, $fil); } if ( !$out) return; list($item) = array_values(preg_grep("|$regex|i", $out)); # error_log(__FUNCTION__ . " Matching items for |$regex|"); # error_log(__FUNCTION__ . " Subdirs in $str: " . join('|', $out)); # error_log(__FUNCTION__ . " Found dir '$item'"); return ($item) ? $item : $str; } class Template { var $fn = null; var $filename = null; var $ch = null; var $error = null; var $searchpath = null; var $searchdir = null; var $inf = null; var $def = null; var $me = 'object'; var $vars = array(); function Template($name) { # Compatibility $this->filename =& $this->fn; $this->me = strtoupper(get_class($this)); $this->searchpath = $GLOBALS[$this->me . "_SEARCH"]; if (defined($this->me . "_COMPRESS")) { foreach(array(array('gzcompress', 'gzuncompress'), array('gzdeflate', 'gzinflate')) as $grp) { if (function_exists($grp[0])) { $this->def = $grp[0]; $this->inf = $grp[1]; break; } } } $this->fn = $name; $this->refresh(); } function set($varname, $value = ''){ $this->vars[$varname] = $value; } function get($varname) { return $this->vars[$varname]; } function refresh() { if (!preg_match('/\.([^\.\/\s]+)$/', $this->fn, $found) ) { $this->cached($this->fn); $this->fn = null; $this->error = null; return; } # Implementatie zoekpad $subdirs = preg_split('/([\s]*;[\s]*)/', $this->searchpath); if (! $subdirs) $subdirs = array(''); list($a, $up, $b, $path) = preg_match('/^(([\.]+\/)*)(.+)/', $this->fn, $found) ? $found : array('', '', '', $found[0]); foreach($subdirs as $subdir) { $sub = _slashjoin($up, $subdir); # Wanneer de basis zoekdirectory niet bestaat, dan controleren we nog even # of deze naam niet partieel voorkomt ergens in de boom. Zie functie _dirlist(). if ($subdir and !is_dir($sub)) { $sub = _dirlist(dirname($sub), preg_replace('/([^0-9a-z]+)$/', '', $subdir) ); } $this->searchdir = _slashjoin($sub, $path); $exists = (file_exists($this->searchdir) and filesize($this->searchdir) > 0); if ($exists) { $this->searchpath = $sub; break; } } $readable = ($exists and is_readable($this->searchdir) ); $soort = ($readable) ? filetype($this->searchdir) : ""; if ($readable and $soort == "file") { $this->cached( join('', file($this->searchdir)) ); $this->error = null; } elseif (!$exists) { $this->error( sprintf("'%s' bestaat niet.", $this->searchdir) ); } elseif (!$readable) { $this->error( sprintf("'%s' kan niet worden gelezen.", $this->searchdir) ); } elseif ($exists && $soort != "file") { $this->error( sprintf("'%s' is geen geldig bestand; %s", $this->searchdir, $soort) ); } return; } function error($str) { $text = sprintf('%s %s [in %s]', $this->me, $str, $_SERVER['SCRIPT_NAME']); $this->error = $text; if ($_SERVER['IS_DEVEL'] and $this->error) error_log($this->error); } function parse($vars = array()) { $vars = $vars + $this->vars; if ($this->searchpath) # Voeg een slash toe aan het einde van het pad - templates verwachten dit! $vars['_searchpath'] = trim(_slashjoin($this->searchpath, ' ')); $match = array(); $repl = array(); foreach(array_keys($vars) as $key){ $match[] = sprintf("/(%%\[%s\]%%)/i", preg_quote($key)); $repl[] = $vars[$key]; } $match[] = '/%\[[^\[\]]+\]%/'; # Catch all $repl[] = ''; return preg_replace($match, $repl, $this->cached()); } function extractData() { $reg = '/<\!--(\s*([^=\s\<\>]+)[\s=]+[\'"]?([^\'"\s\<\>]+))+\s*-->/'; $comment = '/<\!--\s*(.+)\s*-->/'; $fields = '/([^=\s<>]+)[\s=]+([\'\"])?([^\s<>\2]+)/'; if (! preg_match_all($comment, $this->cached(), $found) ) return false; foreach($found[1] as $line) { preg_match_all($fields, $line, $res); for($i=0; $i < sizeof($res[0]); $i++) { $this->vars[$res[1][$i]] = $res[3][$i]; } } return $this->vars; } function cached($str = null) { if (is_null($str)) { #request $do = $this->inf; return ($this->compressed() and $this->ch) ? $do($this->ch) : $this->ch; } $do = $this->def; $this->ch = ($this->compressed()) ? $do($str, 9) : $str; } function compressed() { return ($this->inf || $this->def); } } # EOF ?>