original in en Luis Colorado
en to nl Tom Uijldert
PG2CGI
(Een referentiehandleiding zit al in de
distributie. De URL voor het pakket staat verderop in dit artikel) maar eerder om een kleine
inleiding te geven op dit pakket om lezers aan te sporen het te gebruiken en gelegenheid te
geven tot commentaar.
Verder staat er een leger van webservers en databanken die, in schril contrast, uitblinken in de afwezigheid van hulpmiddelen om beide omgevingen te integreren (de meeste van dit soort hulpmiddelen zijn alleen commercieel te verkrijgen en hebben grote beperkingen voor wat betreft de formaten die het aankan).
Het hier besproken pakket verenigt databank- en web omgevingen. Het ontwerp diende aan de volgende voorwaarden te voldoen:
De meeste mij bekende hulpmiddelen voor het samenvoegen van HTML en databanken, genereren informatie in de uitvoer door het uitbreiden van de set van HTML-tags (een tag is een opmaakopdracht in een gedefinieerd formaat. De definitie van deze tags vormen tezamen de taal HTML); Deze nieuwe tags fungeren vervolgens als macro's. Deze aanpak heeft één groot nadeel: doorgaans moeten we elementen veranderen die binnen de "echte" HTML tags vallen en dat is een grote beperking. Vaak zijn hulpmiddelen hierdoor gedwongen om tags opnieuw "uit te vinden", alleen maar om het standaardeffect te bereiken binnen een bestaande tag. Mijn programma gebruikt M4 intensief om macro-substituties te kunnen doen op een willekeurige plek in de tekst. Het programma zélf genereert geen opgemaakte tekst en is daardoor onafhankelijk van het uiteindelijke formaat van de uitvoer. Het programma genereert een aantal macro's, als resultaat van een query (opvraging) en in een later stadium wordt dit gebruikt door M4 om, in combinatie met een HTML template, een HTML document te genereren.
PG2CGI is oorspronkelijk ontwikkeld om CGI (Common Gateway Interface) op een PostgreSQL
databank aan te sluiten. Al snel besefte men dat het algemeen genoeg was voor gebruik met
andere aansluitingen dan alleen CGI (zoals bijvoorbeeld een gateway tussen een LDAP server
en andere databanken zoals Informix en Oracle).
Nadien is de interface gestandaardiseerd, met daarin alle benodigde functionaliteit en de module PostgreSQL werd herschreven om aan te sluiten op de nieuwe standaard. Het is nu mogelijk om nieuwe drivers te ontwikkelen die een aansluiting mogelijk maken met andere databank software. |
|
Voorbeeld: Stel de cliënt moet informatie doorgeven in de opvraagregel (query_string) en de data moet voldoen aan het volgende formaat:
FIELD=waardeVerder moet de query_string aan dit formaat voldoen en geen additionele informatie bevatten.
Het forceren van deze syntaxis kan eenvoudig worden gedaan met het opgeven van de volgende term in de selectieregel:
QUERY_STRING: "^FIELD=[^&]*$";Deze regel garandeert dat er alleen wat gebeurd als
QUERY_STRING
het
juiste formaat heeft. Dat niet alleen, maar als we het nog eens tussen haakjes zetten dan
kan het programma ook nog de bijbehorende waarde ontleden:
QUERY_STRING: "^FIELD=([^&]*)$";Tegelijkertijd zet het programma ook nog eens de escape codes van het type
%xx
om die uit de navigator komen.
QUERY_STRING: "^FIELD=([^&]*)$";
! HTTP_ADDRESS: "^194\.142\.12\.";(Dit voorbeeld zou de regel ongeldig maken als de aanvraag van 194.142.12.xxx afkomstig is).
[ QUERY_STRING: "USER=([^&]*)" ];Deze term geeft de waarde van de gebruiker door als de cliënt die ook opgeeft. De regel wordt echter niet ongeldig als de cliënt de waarde niet opgeeft.
De linker- en rechterkant van een regel worden afgebakend door accolades "{}" en van elkaar gescheiden door het symbool "->".
De rechterkant heeft hetzelfde formaat: de naam van een variabele, het teken ":", een aantal tekens en ";" als afsluiter. De rechterkant bevat alleen maar toewijzingen aan variabelen die M4 uit moet voeren:
<<<
in de
plaats van >>>
) en geen behandeling van commentaar zodat tekens als
#
geen invloed hebben op de te vervangen regel. Het resultaat daarvan wordt
als waarde toegekend aan de betreffende omgevingsvariabele.
M4FILE
.DRIVER
. term_<i>_match_<j>, waarbij
<i>
het volgnummer is van de term binnen de regel (de eerste term heeft dus
het volgnummer 1, de tweede 2 enzovoorts) en de <j>
refereert aan het
volgnummer van de groep, geteld vanaf links in de reguliere expressie. Als dan de
query_string van de cliënt het volgende is:
`NAME=JAN&FAMILIENAAM1=VAN+HET+HEK&FAMILIENAAM2=GOOR'
en de regel van de website is:
QUERY_STRING: "NAAM=([^&]*)";
QUERY_STRING: "FAMILIENAAM1=([^&]*)";
QUERY_STRING: "FAMILIENAAM2=([^&]*)";
dan zou het resultaat zijn:
term_0_match_0 <- "NAAM=JAN";
term_0_match_1 <- "JAN";
term_1_match_0 <- "FAMILIENAAM1=VAN HET HEK";
(de plustekens zijn vervangen door spaties)
term_1_match_1 <- "VAN HET HEK";
term_2_match_0 <- "FAMILIENAAM2=GOOR";
term_2_match_1 <- "GOOR";
Drivers:
We gaan in dit artikel niet in op de drivers, info daarover is te vinden in de documentatie van de PG2CGI
distributie. Geïnteresseerde lezers worden uitgenodigd om het referentiehandboek te lezen.
Op dit moment is er alleen een driver voor een connectie met PostgreSQL. De schrijver heeft
echter plannen om een tweede te ontwikkelen voor een LDAP-achtige databank.
Een voorbeeld:
Laten we nu de sources bekijken van een volledig voorbeeld.
Neem de mededelingentabel in gedachten van de mededelingen databank bij
slug.ctv.es (volg de AVISO A LOS NAVEGANTES link). Het is een zeer
eenvoudig voorbeeld dat twee templates gebruikt voor het bekijken van één rij uit
de tabel of het maken van een volledige overzichtslijst.
/etc/html2sql.cfg
{
PATH_INFO: "^/avisos/?$"; # Selecteert door PATH_INFO
[SERVER_ADMIN: ".*"]; # Haalt informatie op van SERVER_ADMIN. Optioneel
} -> {
DRIVER: "POSTGRESQL";
PGTTY: "/dev/console"; # Stuurt de logs naar de console
PGDATABASE: "postgres";
# We maken een query (schrijf altijd het oid dat het intern
# in het template bestand zal gebruiken om te linken naar de
# interne records).
PGQUERY: "select oid,ct,titulo,texto,mt"
" from avisos"
" where (dt is NULL or dt > 'now')"
" order by mt desc";
# Het bestand dat het template bevat
M4FILE: "/usr/local/etc/httpd/plantillas_m4/avisos.m4";
WEBMASTER: "term_1_match_0";
#TESTMODE: "TRUE";
}
# De volgende regel laat ons toe om een aankondiging de selecteren (aviso)
# met een gekend OID (primaire sleutel). De informatie zit bij in de variabele
# PATH_INFO van de CGI.
{
PATH_INFO: "^/avisos/([0-9]+)/?$";
SERVER_ADMIN: ".*";
} -> {
DRIVER: "POSTGRESQL";
PGTTY: "/dev/console"; # zoals hierboven, write logt naar de console
PGDATABASE: "postgres";
OID: "term_0_match_1"; # wijs een OID toe
# Ook hier is de selectie belangrijk. We voegen de OID toe aan het
# begin van het veld voor het geval dat we een hyperlink willen schrijven
# om dit veld te wissen.
PGQUERY: "select oid,ct,titulo,texto,mt,dt,autor"
" from avisos"
" where (dt is NULL or dt > 'now') and oid=OID";
# Het template is nu anders
M4FILE: "/usr/local/etc/httpd/plantillas_m4/avisos_oid.m4";
WEBMASTER: "term_1_match_0";
#TESTMODE: "TRUE";
}
/usr/local/etc/httpd/plantillas_m4/avisos.m4
define(<<<for>>>, <<<dnl
ifelse(eval((<<<$2>>>) <= (<<<$3>>>)), 1,
<<<define(<<<$1>>>,<<<$2>>>)$4<<<>>>dnl
for(<<<$1>>>,eval(<<<$2>>>+1),<<<$3>>>,
<<<$4>>>)dnl
>>>)dnl
>>>)dnl
divert(0)dnl
Mime-Version: 1.0
Content-type: text/html
<HTML>
<BODY BGCOLOR="#ffffff">
<CENTER>
<H1>AVISOS A LOS NAVEGANTES QUE PASAN
POR SLUG</h1>
</center>
<B>Nota:</b> Esta sección ha sido
creada para dar a conocer
cualquier noticia de interés relacionada
con
<A HREF="http://slug.ctv.es/">SLUG</a>,
<A HREF="http://LuCAS.ctv.es/">LuCAS</a>,
<A HREF="http://www.HispaLinux.ctv.es/">HispaLinux</a>
y en general, cualquier servicio prestado por <B>slug.ctv.es</b>.<p>
<CENTER><HR WIDTH=100></center>
ifelse(PGRES_RESULTSTATUS, <<<PGRES_TUPLES_OK>>>,<<<dnl
ifelse(PGRES_NTUPLES, 0,<<<dnl
<!-- la tabla est\xe1 vac\xeda -->
No hay avisos.<p>
>>>,<<<dnl /* PGRES_NTUPLES != 0 )( */
<CENTER>
<!-- contenido de la
tabla -->
<TABLE>
<TR>
<TH></th>
<TH ALIGN="LEFT">Fecha-Hora </th>
<TH ALIGN="LEFT">Asunto </th>
</tr>
for(<<<i>>>,0,eval(PGRES_NTUPLES-1),<<<dnl
<TR>
<TD>
<A HREF="/cgi-bin/pg2cgi/avisos/cell(i,0)">
<IMG SRC="/icons/burst.gif">
</a>
</td>
<TD><B>cell(i,1) </b></td>
<TD>cell(i,2) </td>
</tr>
>>>)dnl /* for */
</table>
</center>
>>>)dnl /* PGRES_NTUPLES */
>>>,<<<dnl /* ifelse PGRES_RESULTSTATUS )(*/
Error en el resultado: <B>PGRES_RESULTSTATUS</b><BR>
Mensaje del servidor: PGRES_ERRORMSG<P>
>>>)dnl
<CENTER><HR WIDTH=100></center>
<FONT SIZE=-2>
<A HREF="mailto:WEBMASTER?subject=TABLON
DE ANUNCIOS"><CODE>WEBMASTER</code></a>
</font>
</body>
</html>
/usr/local/etc/httpd/plantillas_m4/avisos_oid.m4
divert(-1)
$Id: generic_list.m4,v 1.1 1998/07/06 17:13:33 luis Exp $
define(<<<cell>>>, <<<PGRES_CELL_$1_$2>>>)
define(<<<field>>>, <<<PGRES_FNAME_$1>>>)
define(<<<for>>>, <<<dnl
ifelse(eval((<<<$2>>>) <= (<<<$3>>>)), 1,
<<<define(<<<$1>>>,<<<$2>>>)$4<<<>>>dnl
for(<<<$1>>>,eval(<<<$2>>>+1),<<<$3>>>,
<<<$4>>>)dnl
>>>)dnl
>>>)dnl
divert(0)dnl
Mime-Version: 1.0
Content-type: text/html
<HTML>
<BODY BGCOLOR="#ffffff">
<CENTER>
<H1>AVISO OID</h1>
</center>
<CENTER><HR WIDTH=100></center>
ifelse(PGRES_RESULTSTATUS, <<<PGRES_TUPLES_OK>>>,<<<dnl
ifelse(PGRES_NTUPLES, 0,<<<dnl
<!-- la tabla est\xe1 vac\xeda -->
No existe el aviso OID, o ha caducado.<p>
>>>,<<<dnl /* PGRES_NTUPLES != 0 )( */
<CENTER>
<!-- contenido de la
tabla -->
<TABLE>
<TR VALIGN="BASELINE">
<TD ALIGN="RIGHT" NOWRAP><font color="#808000"><B>Fecha de entrada:</b></font>
</td>
<TD width="80%">cell(0,1)</td>
</tr><TR
VALIGN="BASELINE">
<TD ALIGN="RIGHT" NOWRAP><font color="#808000"><B>Fecha última
modif:</b></font> </td>
<TD>cell(0,4)</td>
</tr><TR
VALIGN="BASELINE">
<TD ALIGN="RIGHT" NOWRAP><font color="#808000"><B>Fecha eliminación:</b></font>
</td>
<TD WIDTH=*>cell(0,5)</td>
</tr><TR
VALIGN="BASELINE">
<TD ALIGN="RIGHT" NOWRAP><font color="#808000"><B>Autor:</b></font>
</td>
<TD><font size=+1><a href="mailto:cell(0,6)?subject=[TABLON-SLUG]
cell(0,2)">cell(0,6)</a></font></td>
</tr><TR
VALIGN="BASELINE">
<TD ALIGN="RIGHT" NOWRAP><font color="#808000"><B>Asunto:</b></font>
</td>
<TD><font size=+1><B>cell(0,2)<B></font></td>
</tr><TR>
<TD COLSPAN=2 BGCOLOR="#c0ffff"><font color="#404040">cell(0,3)</font></td>
</tr>
</table>
</center>
>>>)dnl /* PGRES_NTUPLES */
>>>,<<<dnl /* ifelse PGRES_RESULTSTATUS )(*/
Error en el resultado: <B>PGRES_RESULTSTATUS</b><BR>
Mensaje del servidor: PGRES_ERRORMSG<P>
>>>)dnl
<CENTER><HR WIDTH=100></center>
<FONT SIZE=-2>
<A HREF="mailto:WEBMASTER?subject=TABLON
DE ANUNCIOS"><CODE>WEBMASTER</code></a>
</font>
</body>
</html>
Het resultaat kan worden bewonderd op de volgende URLs:
http://slug.ctv.es/cgi-bin/pg2cgi/avisos/
of
http://slug.ctv.es/cgi-bin/pg2cgi/avisos/20384
Ophalen
Het programma PG2CGI kan bij de volgende URLs op worden gehaald:
http://slug.ctv.es/~luis/utils/pg2cgi.tar.gz
http://slug.ctv.es/~luis/utils/pg2cgi.README
ftp://slug.ctv.es/pub/slug/luis/pg2cgi.tar.gz
ftp://slug.ctv.es/pub/slug/luis/pg2cgi.README