minivend


MiniVend -- multi-catalog shopping cart and mall

Version

This document describes MiniVend 3.07, based on Andrew Wilcox's original Vend, Version 0.2, with portions from Vend 0.3.


OVERVIEW OF MINIVEND

If you want to get started, just jump to QUICK START below. The following section describes how MiniVend works.

The Vend Concept

MiniVend is a descendent of Vend, originally developed by Andrew Wilcox. Though the original Vend was much simpler than MiniVend in implementation, the basic concept remains unchanged. Quite simply, MiniVend maintains its own set of pages, outside of regular HTML space, which contain special tags that are interpreted by MiniVend.

The tags, which are in [square brackets], are interpreted by MiniVend and many different values can be substituted. Some examples are:

User form input
MiniVend remembers input by a user from form to form, and the value of any form variable is ``remembered'' and inserted upon finding a [value input_field] tag. The input_field is a normal HTML form field.

Database contents
MiniVend can have an unlimited number of attached databases, either in one of its own internal formats or attached via SQL/ODBC. The contents of a database can be referenced with tags like [data table=products field=name key=334-12].

Session parameters
Things like where the user originally found your catalog ([data session source] and [data session referer]), domain they are from ([data session host]), the time of their last access ([data session time]), and many other parameters.

File contents or program output
You can insert the contents of an outboard file with [file directory/file], or the output from an arbitrary program (given proper permission from your administrator!).

Searches of files
MiniVend supports different search engines, including Glimpse , or you can call your own and have MiniVend process the output for you.

There are over 80 different distinct tags supporting hundreds of functions..

A typical user session

The user hears about your catalog via a search engine, link from another page, or click-thru from a banner ad. They access the link, which is a URL pointing to the MiniVend link program (called VLINK or TLINK, more on that below). The MiniVend server is already running on your system, and your catalog has been designed and tested.

The link program, which is a regular CGI program, calls the MiniVend server. The MiniVend server sees the path information which is appended to the URL calling it, and brings up the corresponding page. The page contains a link to order items from your catalog.

The user clicks on the link and MiniVend looks in the a products database, finds the item, and places it in the user's shopping cart. (Each user has a separate shopping cart, which is attached to their session .)

Once the user decides to purchase, they check out by filling out a form with their name, address, payment information, etc. In the process they may make choices about how the product should be shipped, how they will pay, and provide any other information you may ask for. They then place (or ``submit'') the order.

Their payment may be taken at that point via CyberCash and a soft-goods product downloaded -- or their order information may be simply sent to you, the store owner, via encrypted email or FAX. The order is saved to a file or database table as backup, or in the case of fully-automated systems sent directly to an order entry program or database link.

All of these operations are fully configurable by you. The base MiniVend distribution includes a sample store -- some users have simply customized the text and images inside, changed the database entries, and opened their store. You will probably want to fully customize for a distinctive catalog look and feel.

How MiniVend Manages Sessions

Normally, each request for a World Wide Web page which comes in to a server stands on its own. While the server will probably know which machine a request comes from, it may not know if the next request comes from the same browser or even from the same user on that machine.

MiniVend keeps track of who is ordering what by including in the URL a session id , which is a random piece of text which is different for each customer browsing the catalog.

This session ID is either tracked with cookies, or it can be passed along through special URLs within catalog pages. Pages in the catalog served by MiniVend running as a cgi-bin program generate a special URL for every link. Here is an example of such a URL:

http://machine.company.com/cgi-bin/simple/browse?WehUkATn;arg;1

An explanation of each part:

machine.company.com
Internet address of the server hosting the MiniVend catalog.

cgi-bin
Informs server that the requested page will be generated by a program.

simple
Name of the program to run

browse
Page of the catalog to display

WehUkATn
The session ID

;
Separates session ID from argument.

arg
An argument which can be used by MiniVend to select page display options.

;
Separates argument from the unique integer.

1
A unique integer (or source code, if it contains a letter) which prevents caching servers from caching the URL.

.

Page Delivery

MiniVend pages are written in regular HTML with extensions to support catalog ordering. MiniVend extensions look like:

[page specials]See our specials![/page]

Pages are delivered through the following steps:

.


DISTRIBUTION AND SUPPORT INFORMATION

MiniVend is normally free of charge, and is distributed under a modified GNU general public license. This means that individuals and organizations, both commercial and non-commercial, may generally use MiniVend without charge.

The only exception is that any individual or organization using uninvited email solicitations (commonly known as SPAM) may not use MiniVend for a period of one year from their last SPAM incident. Upon sending of SPAM, the user must immediately discontinue using MiniVend

Once their Internet Service Provider (or network backbone provider) is notified by the author, they must discontinue use of MiniVend. Use of MiniVend after such a notification is subject to a US$1,000 per day license fee payable to the author.

If such an individual uses MiniVend, let the author know and an immediate investigation will be started.

MiniVend is not guaranteed to be supported other than by making full source code available. If it breaks you get to keep both pieces. However, the author is always looking to improve MiniVend and sometimes answers questions. The more concise and better-researched your question, the more likely it is to get an answer. No tutorials will be provided, though. You have to learn all of this stuff on your own.

Where to Download MiniVend

The MiniVend version described in this document is available from:

http://www.minivend.com/minivend/download.html

You can also go to any CPAN archive and access the directory authors/id/MIKEH.

Perl

You will need Perl version 5.004 or higher to run MiniVend 3.07. Many sites are still running lower Perl versions. In addition, on systems that do not have GDBM or DB_File installed, memory problems may occur. Large catalogs will use large amounts of memory if the databases must all reside there.

You can download the latest Perl 5 from any CPAN (Comprehensive Perl Archive Network) site. Here are some of the many:

NORTH AMERICA

Florida ftp://ftp.cis.ufl.edu/pub/perl/CPAN/ Illinois ftp://uiarchive.cso.uiuc.edu/pub/lang/perl/CPAN/ Massachusetts ftp://ftp.delphi.com/pub/mirrors/packages/perl/CPAN/ Oklahoma ftp://ftp.uoknor.edu/mirrors/CPAN/ Texas ftp://ftp.metronet.com/pub/perl/ ftp://ftp.sedl.org/pub/mirrors/CPAN/ ftp://ftp.sterling.com/programming/languages/perl/

EUROPE

Czech Republic ftp://sunsite.mff.cuni.cz/Languages/Perl/CPAN/ Finland ftp://ftp.funet.fi/pub/languages/perl/CPAN/ France ftp://ftp.ibp.fr/pub/perl/CPAN/ ftp://ftp.pasteur.fr/pub/computing/unix/perl/CPAN/ Germany ftp://ftp.leo.org/pub/comp/programming/languages/perl/CPAN/ ftp://ftp.rz.ruhr-uni-bochum.de/pub/programming/languages/perl/CPAN/ Great Britain ftp://ftp.demon.co.uk/pub/mirrors/perl/CPAN/ ftp://unix.hensa.ac.uk/mirrors/perl-CPAN/ The Netherlands ftp://ftp.cs.ruu.nl/pub/PERL/CPAN/ Poland ftp://ftp.pk.edu.pl/pub/lang/perl/CPAN/ Portugal ftp://ftp.ci.uminho.pt/pub/lang/perl/ Slovenia ftp://ftp.arnes.si/software/perl/CPAN/ Sweden ftp://ftp.sunet.se/pub/lang/perl/CPAN/ Switzerland ftp://ftp.switch.ch/mirror/CPAN/

AUSTRALASIA

Australia ftp://coombs.anu.edu.au/pub/perl/CPAN/ ftp://ftp.mame.mu.oz.au/pub/perl/CPAN/ New Zealand ftp://ftp.tekotago.ac.nz/pub/perl/CPAN/

ASIA

Japan ftp://ftp.lab.kdd.co.jp/lang/perl/CPAN/ Taiwan ftp://dongpo.math.ncu.edu.tw/perl/CPAN/

AFRICA

South Africa ftp://ftp.is.co.za/programming/perl/CPAN/

Setup for HTTP Servers

The most important issue with MiniVend is the permissions with which the CGI program and the MiniVend server run.

MiniVend uses a server running in the background, with a small C program (generically called vlink) that communicates with MiniVend via a UNIX-domain socket.

To improve security, MiniVend normally runs with the socket file having 0600 permissions (rw-------), which mandates that the CGI program and the server run as the same user ID. This means that the vlink program must be SUID to the same user ID as the server executes under. (Or that CGIWRAP is used on a single catalog system).

With MiniVend 3.0 multiple catalog capability, the permissions situation gets a bit tricky. MiniVend comes with a program, makecat, which configures catalogs for a multiple catalog system. It should properly set up ownership and permissions for multiple users if run as the superuser.


QUICK START

Obtain, decompress and untar the distribution:

gzip -dc minivend-3.07.tar.gz | tar xvf -

NOTE FOR WINDOWS: Windows users need to unzip the file with whatever program they use, or obtain the self-extracting executable.

Before installing, check the site where you obtained MiniVend for any patches that might have been issued since the release.

Change to the created directory, something like:

cd minivend-3.07

Run the configure script with:

./configure

NOTE FOR WINDOWS: Type configure instead. The ./ is needed for UNIX users with a properly setup shell.

If you have trouble with ./configure, try this:

perl Makefile.PL make make test make install

Replace the perl with the proper path to your Perl 5.004 or higher binary.

You will be asked for the directory where you want to install MiniVend -- any directory will do. You must of course have write permission there; and you will eventually need to have write permission on your CGI-BIN and HTML directories. This directory is referred to later in the documentation as VendRoot or the MiniVend software directory.

The process should be self-explanatory. If you have trouble answering the questions asked, look closely at the examples provided. If you still have trouble, you will need to find a tutorial about the World Wide Web -- the WWW FAQ at www.boutell.com would be a good place to look.

If you discover any problems, refer to the section IYou will want separate directories to hold the catalog pages and databases. The makecat program supplied with MiniVend will make those for you.

IMPORTANT NOTE: One point that is to be emphasized -- only your base html pages go in the document space of your http server. Any pages with MiniVend elements/tags go in the directory set by the PageDir directive (the default is ~/catalogs/catalog_name/pages). For the demos supplied with MiniVend, this means that only a few pages will be copied to your HTML directory, with the remainder of the pages staying in the directory defined as PageDir .

If you are on an ISP where all of your files are in HTML document space, you should disable all access to your MiniVend catalog directory with the proper HTTP access restrictions. Normally that is creating a .htaccess file like this:

<Limit GET POST> order allow,deny deny from all </Limit>

If you are unable to do this, it is recommended that you do not run MiniVend. If you can set file permissions such that files will not be served, it may be OK, but security will be a problem. Please be careful with your customers' personal information.

Setting up multiple catalogs

MiniVend has multiple catalog capability. It breaks the configuration files into two pieces:

minivend.cfg
This file is located in the main MiniVend directory, and has only a few server-wide configuration parameters. The most important is the Catalog directive, which sets up the catalog configuration.

The Catalog directive defines which catalogs will be created at server startup.

Catalog simple /home/catalogs/simple /cgi-bin/simple /secure-bin/simple

simple
The catalog identifier , used as the name of the catalog on command lines. In the supplied demo configuration this would be simple . The identifier can contain characters from the set [A-Za-z0-9_].

/home/catalogs/simple
The directory where the catalog.cfg file may be found, and usually the directory where pages and databases are kept.

/cgi-bin/simple /secure-bin/simple
The script names which, when containing a MiniVend link program, will cause that catalog to be called. At least one must be supplied, and the same name may not be used for more than one catalog unless the FullURL directive is specified, in which case the parameter may be specified as www.yourcompany.com/cgi-bin/simple and www.theirs.com/cgi-bin/simple may call a different catalog.

There may also be SubCatalog directives:. SubCatalog easy simple /home/catalogs/simple /cgi-bin/easy

easy
The name of the subcatalog, which also controls the name of the subcatalog configuration file -- in this case easy.cfg .

simple
The name of the base configuration, which will be the basis for the catalog. Parameters in the easy.cfg file that are different will override those in the catalog.cfg file for the base configuration.

The remaining parameters are as in the Catalog directive.. Additional minivend.cfg parameters set up administrative parameters that are catalog wide -- see Server Configuration File for details on each of these.

Each catalog can be completely independent, with different databases -- or catalogs can share any or all pages, databases, and session files. This means that several catalogs can share the same information, allowing ``virtual malls''.

The Catalog

MiniVend pages are NOT in normal HTML space. They are contained in the catalog directory . Each individual catalog must have its own base directory. The catalog directory has this structure by default:

catalog.cfg
File containing configuration directives for this catalog. (Subcatalogs have differing information in a file named for the subcatalog.)

config
Directory that will be read when directives are set with the config/static.pages will be read when the directive

StaticPage <static.pages

is encountered in the catalog.cfg file.

error.log
File which contains catalog-specific errors. Check this file when something doesn't work right. It is also where any syntax errors in embedded Perl code will be shown.

etc
Directory that contains logs, scratch files, and cache files.

pages
Directory that contains the pages of your catalog. This can be considered to be the ``document root'' of the catalog. Pages contained therein are called with the path information after the script name -- i.e. /cgi-bin/simple/products/gold will call the page in the file pages/products/gold.html .

products
Directory containing database source files, including the special MiniVend databases shipping.asc, accessories.asc, pricing.asc (and other shipping database files)

reconfig
A script file, which when executed, will cause the catalog.cfg file to be re-read and the catalog configuration to change. If errors occur, the catalog will stay with its old/previous configuration. This script is set up by the makecat program, but may require editing if you deviate from the standard MiniVend configuration. It operates by executing the link program that is contained in the CGI directory and passing the proper parameters through the environment.

session
Directory which contains session files when DBM sessions are not in use.

session.gdbm (or session.db)
The GDBM or DB_File session database file. This is a DBM database that contains the user sessions.

.

If something goes wrong

MiniVend is a complex program, and needs the services of other complex programs to work. When there is a problem, it is not always MiniVend. It may have to do with Perl or your HTTP server. In fact, in the over two years of MiniVend's existence more basic installation problems have to do with those than with MiniVend itself.

If you get a message about not being able to find libraries, or if you get a core dump or segment fault message, it is always improperly built or configured Perl and has nothing to do with MiniVend. Contact your system administrator or install a new Perl yourself.

The makecat program is intended to be used to create the starting point for the catalog. If you don't get the demo to work the first time, keep trying. If you still can't get the demo to work, try running in INET mode. Finally, see the MiniVend FAQ at:

http://www.minivend.com/minivend/faq/

Check the two error log files -- error.log in the MiniVend home directory (where minivend.cfg resides) and error.log in the catalog directory (where catalog.cfg resides; there can be many of these). Many problems can be diagnosed quickly if these error logs are consulted.

Check the README file, the FAQ, and mail list archive at the official MiniVend web site for information:

http://www.minivend.com/minivend/

You may subscribe to the MiniVend users mail list by sending the message text subscribe minivend-users to:

majordomo@minivend.com

Double check that you have the following things:

  1. The vlink program is SUID, or you have made appropriate changes in the ReadPermission and WritePermission directives. Unless the files are world-writable, the vlink program and the MiniVend server must run as the same user ID!

    If you have trouble with the vlink program (named simple in the demo configuration), try re-running makecat and using INET mode instead. (Or you can copy the tlink INET mode link program over vlink). This should work unchanged for many systems, but if you are on an ISP or have a non-standard network configuration you may have to make some changes to minivend.cfg . For tlink to work you must have the proper host name(s) configured into the TcpHost directive in minivend.cfg . The program selects port 7786 by default (the ASCII codes for ``M'' and ``V'') -- if you decide to use another port, you must set the same number in both the tlink program (before compilation, or by editing tlink.pl) and the minivend.cfg file.

    The tlink program does not need to be SUID.

  2. That you have proper file permissions.

    IMPORTANT NOTE: The MiniVend server should not run as the user nobody!

    The program files can be owned by anyone, but any databases, ASCII database source files, error logs, and the directory that holds them must be writable by the proper user ID, that is the one that is executing the minivend program. The best way to operate in multi-user, multi-catalog setups is to create a special minivend user, then put that user in the group that each catalog user is in. If you can define a group for each individual user, that provides the best security. Then all associated files can be in 664 or 775 mode, and you should have no problems with permissions.

  3. The vlink program is being executed on a machine that has the socket file etc/socket on a directly attached disk. UNIX-domain sockets will not work on NFS-mounted filesystems! That means the server minivend and the CGI program vlink must be executing on the same machine.

    The tlink program does not have this problem, but it must have the proper host name(s) and TCP ports set in the TcpHost and TcpPort directives in minivend.cfg . Also, you should be careful of security if sensitive information like customer credit card numbers is being placed on a network wire.

MiniVend is an ambitious and complex program, and is not presented as.being easy to use , easy to install , or bug-free. The configuration scripts were done to try and make a very painful process only slightly painful. Some people install in one pass. Others never make it, especially when they are running on an ISP with a restrictive setup. Determined and thoughtful users almost always make MiniVend work.


SETTING UP YOUR CATALOG

MiniVend uses its own tags to implement catalog functions -- they are similar to normal HTML, but are in [square brackets]. They will be referred to as either tags or elements in this document.

In order to set up a custom catalog, there are a number of steps.

You will need to become familiar with the MiniVend tags and directives to make your own catalog. The demo catalogs are a good starting point, but are not a finished product.

Start with a database

The first thing you must do is develop your product database. This might contain all of the information used to display pages about your products -- or just the product code (SKU), short description, and price. At the minimum, those three fields are required.

Some other things you might put in:

image
A database field giving the name of an image file to display the product. Alternatively, you can keep images in files that are named for the product code -- then display them if they exist (use the [if file file.gif] TAG [/if] construct).

nontaxable
This field should be present if you have items that do not have sales tax calculated for them.

size
A comma-separated string containing product size information, for example: Small, Medium, Large, XL

You can also define any other attribute information in a database field.

weight
The shipping weight of an item is useful for UPS lookup or other weight-based shipping calculations.

category
If you wish to do one-click category searches to build product directories, you might use this field to select on.

related
Items related to the item in the record. Using MiniVend's [loop item] tag, you could build product subclasses and accessory sets.

.

On-the-fly pages, static, or both?

The on-the-fly page capability of MiniVend makes it easy to build your catalog without hard-coding a single page. To build category pages, use the one-click search and a the search result page(s). To build single-item pages, use the flypage.html template as an example and build your own. You can also define a product database field (with the PageSelectField directive) to hold the name of the base on-the-fly page for that item. You might define it to be the same as the category of product, for example.

If you have a large catalog, you will almost certainly want to use the on-the-fly page for most products. But if you want to mix in a few extra-special pages, perhaps for your best sellers, you can do so. Just build the pages and place them in files corresponding to the part number (in the MiniVend pages directory, of course -- not your HTML directory). They will take precedence over the on-the-fly page.

If you have only a small number of products, hard coded pages are just fine, though you would be surprised how much of a maintenance headache they are compared to database definitions. Build them just about like normal HTML pages, except for the MiniVend tags to order the item. Place them wherever they can be reached -- if you are using searches, you will want to name the file by the part number, or at least make a link to it.

Some other things you might put in:

Images
You can easily place a thumbnail image (even with a link to a blowup) only for those items that have them.

Accessories
The accessories database allows you to pre-define additional products to offer with a main product.

Reviews/Testimonials
You can key the placement on the existence of a file in a certain directory.

.

Use the demo catalogs

The demo catalogs supplied with MiniVend are there to give you a starting point for your own catalog. Play with them, change them, and rename them -- add your own icons, change flypage.html, change the results.html files, etc.

Tree design

Determine how users will enter and exit your catalog. There are quite complex and intelligent conditional schemes possible, especially if you use the Cookies capability, but simplicity is often the easiest and most reliable.

The Essentials

The rest of this section describes the rest of the things you need to know to make the most basic of MiniVend catalogs, one which displays pages and uses the demo shopping basket and checkout sequence. If you want to add custom features, like special shipping charges and sales tax, you will need to go much further. But this will get you started.

All of the mentioned features (and more) are demonstrated in the simple demo catalog.

Catalog Pages -- MiniVend tags

Pages in the catalog are written in regular HTML with extensions to support catalog ordering. To distinguish them from regular HTML, these extended elements use [square brackets] instead of angular brackets. We will usually call them MiniVend tags or just tags.

These tags perform various display and modification operations for the user session. The tag names and their general function are:

accessories Access product accessory functions area Insert a re-written MiniVend URL areatarget Insert a re-written MiniVend URL with frame body Insert a predefined <BODY ...> HTML tag buttonbar Insert a predefined buttonbar calc Perform Perl calculations (low overhead) /calc cart Set the current shopping cart name checked Conditionally check an HTML check/radio box comment Insert comments in MiniVend pages /comment compat Define regions to be interpreted with old syntax /compat col Used with [row] -- rudimentary text tables for order reports /col condition Sets a condition inside [if explicit] and others /condition currency Formats a number like currency for current locale /currency data Access a database or user session element default Insert a variable but with a default response if blank description Output a product description discount Set a product discount coupon /discount discount-price Show the discounted price else Defines else region for [if ...], [if-field ..] and others /else elsif Defines elsif region for [if ...] /elsif field Access a product database field file Insert the contents of a file finish-order DEPRECATED. Conditionally show a "check basket" link. fly-list Show an item "on-the-fly" in an arbitrary page /fly-list framebase DEPRECATED. Set a <BASE FRAME="..."> only if in frames mode. frames-off Turn off MiniVend frames mode. frames-on Turn on MiniVend frames mode. help DEPRECATED. Show a help message only if help is enabled. if Perform any of many conditional tests /if if-data Display region only if database element non-empty /if-data if-field Display region only if field non-empty /if-field if-loop-data Display region only if database element non-empty /if-loop-data if-loop-field Display region only if field non-empty /if-loop-field if-modifier Display only if item attribute/modifier set /if-modifier if-sql-data Display region only if database element non-empty /if-sql-data if-sql-field Display region only if field non-empty /if-sql-field include Include a file with complete MiniVend interpretation item-accessories Product accessory functions (set select box) item-code Insert current item SKU/code/part number item-data Insert data entry corresponding to current SKU item-description Insert description corresponding to current SKU item-discount Show amount of discount for current SKU item-field Insert product database entry corresponding to current SKU item-increment Count for list item-last Stop displaying if condition is met /item-last item-link DEPRECATED. Auto-HTML link to product page. item-next Skip item if condition is met /item-next item-list Iterate over a shopping cart /item-list item-modifier Show value of item attribute/modifier item-param DEPRECATED. Show element from positional list. item-price Display price of item with any discounts/price breaks/adjustments item-quantity Show quantity ordered on shopping cart line item-subtotal Subtotal for the item (item-quantity * item-price) last-page DEPRECATED. /last-page lookup Lookup an item in a database if not already set loop Iterate over an arbitrary list /loop loop-accessories Product accessory functions (set select box) loop-change Grouping of items in list display /loop-change loop-code Insert current item SKU/code/part number loop-data Insert data entry corresponding to current SKU loop-description Insert description corresponding to current SKU loop-field Insert product database entry corresponding to current SKU loop-increment Count for list loop-last Stop displaying if condition is met /loop-last loop-link DEPRECATED. Auto-HTML link to product page. loop-next Skip item if condition is met /loop-next loop-price Display price of item matches Show number of matches from search modifier-name Place a variable name that corresponds to an attribute more Show region of search list only if more matches more-list Display more matches list with links to next series /more-list sql Perform any of several types of SQL query sql-code Insert current item SKU/code/part number sql-data Insert data entry corresponding to current SKU sql-description Insert description corresponding to current SKU sql-field Insert product database entry corresponding to current SKU sql-increment Count for list sql-link DEPRECATED. Auto-HTML link to product page. sql-param DEPRECATED. Show element from positional list. sql-price Display price of item no-match Define area of search results page displayed when no match /no-match new Set new syntax for this page nitems Show number of items for a shopping cart old Set old syntax for this page order Create HTML link to order an item /order on-change Grouping of items in list display /on-change page Create A HREF with re-written URL to call MiniVend page /page pagetarget Create A HREF with re-written URL for frames MiniVend page /pagetarget perl Embed output of arbitrary Perl in the page /perl post DEPRECATED. Force region to be interpreted last. /post price Show price of an item process-order Create URL for MiniVend form processing, retain security setting process-search Create URL to call MiniVend form-based search process-target Create URL to call MiniVend form processing quantity-name Place a variable name that corresponds to item quantity random Insert a random banner rotate Insert a rotating banner row Used with [col] -- rudimentary text tables for order reports /row salestax Show amount of salestax for shopping cart scratch Access a scratch variable search Do a MiniVend search, output list of returned item codes search-list Display output of a MiniVend search /search-list selected Conditional selection of drop-down <SELECT ...> set Set a scratch variable /set shipping Calculate shipping shipping-desc Show shipping description sort Set sort order for iterating lists /sort subtotal Calculate subtotal without tax or shipping tag Miscellaneous functions /tag then Define THEN region for [if ...] /then total-cost Calculate order total with tax, handling, and shipping uniq Remove duplicate search returns value Display form value

The syntax for each tag is displayed in the documentation below.

The first page displayed in the catalog, if no argument is supplied to the vlink or tlink cgi-bin program, is ``catalog.html''. This page will contain links to other catalog pages with the [page pagename] tag. Individual products can be ordered by the [order <item-code>] element, which brings up the shopping basket page. The shopping basket page contains an [item-list], which builds information on each item ordered, and optionally has input boxes for the customer to type in their name and address. If desired, the customer can be ``stepped through'' the order process (as is demonstrated in the supplied demos). Once the order has been sent the receipt page is displayed.

Unless you are using the HTTP cookie support, you will normally not want to include regular hypertext links to pages outside of the catalog. Such links will not include the session id, which means that if the customer follows an external link back to the catalog the list of products ordered so far will have been lost.

Inline images, on the other hand, are served in the normal fashion. You should include a regular <IMG SRC=``URL''> element, where the URL refers to a graphic image. You cannot use relative image names as you would in an HTML document! MiniVend has the capability of defining an image directory (with the ImageDir directive) that automatically adjusts your image path to a set base directory.

MiniVend has a powerful static page-building capability. This allows you to pre-build catalog pages that don't contain dynamic elements (such as order/shopping basket status) into HTML, then automatically point the browser to those pages when appropriate. This reduces the number of pages that MiniVend must parse in real time, and can increase server capacity by orders of magnitude. See STATIC PAGE BUILDING .

Cookies

All you need to do to have users with cookie-capable browsers retain session context is enable the Cookies directive. You can then intermix standard HREF and MiniVend page links without fear of losing the shopping basket. Cookie capability is also required to use search caching, page caching, and statically generated pages. If the browser does not support cookies, the cache will be ignored.

If you plan to use more than one host name within the same domain for naming purposes (perhaps a secure server and non-secure server) then you can set the domain with the CookieDomain directive. This must contain at least two periods (.) as per the cookie specification, and you cannot set a domain that your server is not located within.

Basic MiniVend Tags

NOTE: In the descriptions, parameters marked with an asterisk* are optional.

When a tag is separated by an underscore, as in item_list, a dash is just as appropriate (i.e. item-list). They are interchangeable, except that the ending tag and beginning tag should match (don't use [item-list] list [/item_list]).

[value field flag*]
Expands into the current value of the customer/form input field named by field. If flag is present, single quotes will be escaped with a backslash; this allows reliable SQL inserts.

[page pg arg*]
(new syntax [page href=``dir/page'' target=``frame'' arg=``argument''])

Insert a hyperlink to the specified catalog page pg. For example, [page shirts] will expand into < a href=``http://machine.company.com/cgi-bin/vlink/shirts?WehUkATn;;1''>. The catalog page displayed will come from ``shirts.html'' in the pages directory.

The additional argument will be passed to MiniVend and placed in the {arg} session parameter. This allows programming of a conditional page display based on where the link came from. The argument is then available with the tag [data session arg], or the embedded Perl session variable $Safe{'session'}->{arg}. If you set the catalog configuration option NewEscape , then spaces and some other characters will be escaped with the %NN HTTP-style notation and unescaped when the argument is read back into the session.

A bit of magic occurs if MiniVend has built a static page for the target page. Instead of generating a normal MiniVend-parsed page reference, a static page reference will be inserted if the user has accepted and sent back a cookie with the session ID.

[area pg arg*]
(new syntax [area href=``dir/page'' target=``frame'' arg=``argument''])

Like the areatarget element, except it will never yield a frame target.

The optional arg is used just as in the page tag.

[/page]
Expands into </a>. Used with the page element, such as:

[page shirts]Our shirt collection[/page].

TIP: A small efficiency boost in large pages is to just use the </A> tag.

.

How to order an item

MiniVend can either use a form-based order or a link-based order to place an item in the shopping cart. The link-based order uses the special [order item-code] tag:

[order code cart/page* database*]
(new syntax [order code=``code'' href=``cart/page'' base=``database''])

Expands into a hypertext link which will include the specified code in the list of products to order and display the order page. code should be a product code listed in one of the ``products'' databases. The optional argument cart/page selects the shopping cart the item will be placed in (begin with / to use the default cart main) and the order page that will display the order. The optional argument database constrains the order to a particular products file -- if not specified, all databases defined as products files will be searched in sequence for the item.

Example:

Order a [order TK112]Toaster[/order] today.

[/order]
Expands into </a>. Used with the order element, such as: Buy a [order TK112]Toaster[/order] today.

To order with a form, you set the form variable mv_order_item to.the item-code/SKU and use the refresh action:

<FORM ACTION="[process-target]" METHOD=POST> <INPUT TYPE=hidden NAME="mv_todo" VALUE="refresh"> <INPUT TYPE=hidden NAME="mv_order_item" VALUE="TK112"> Order <INPUT NAME="mv_order_quantity" SIZE=3 VALUE=1> toaster <INPUT TYPE=submit VALUE="Order!"> </FORM>

You may also specify attributes like size or color at time of order, and may batch select whole groups of items. Read further to see how, or order the T-shirt from the more details page of the simple demo to see how it is done.

Where do I go from here?

MiniVend is very complicated but very powerful. If you have read and understood the documentation so far, you have a good start on building a catalog. There are many, many, more features than are shown in the demo, and mastering the ones you need will take time. Thousands of people have built MiniVend catalogs -- you can too. If you feel it is beyond you, then we would suggest engaging a competent consultant. Good luck!


DATABASES

MiniVend, as with most powerful shopping cart programs, is all about databases.

This version of MiniVend implements the database in GDBM, DB_File, SQL, or in-memory format. If you have DBM, large catalogs can be used without using too much memory. The DBM files are built automatically when they change, from the the ASCII source file. If you don't have either GDBM or DB_File, or you set the environment variable MINIVEND_NODBM before starting the server, an in-memory product database will be used. Catalogs of more than, say, 1,000 items will use large amounts of memory.

Support for SQL databases is included. Form-based updates and inserts allow user input and remote maintenance. No other database besides MiniVend's internal one is needed -- but you may find that keeping your database in an SQL manager makes it easier to integrate MiniVend with other tools.

NOTE: In the following descriptions, we will use the following terms interchangeably:

key, code
Either one is a reference to the key for the database. In MiniVend this is often the product code or sku, which is the part number for the product. Other key values may be used to generate relationships to other database tables.

It is required that the key be the first column of an ASCII source file for GDBM, Berkeley DB, or in-memory built-in database formats. It is also strongly suggested that you keep that practice for SQL databases, since MiniVend's import, export, and search facilities will work much better with that practice.

field, column
This is a column of the database. One of the columns is always the key -- MiniVend prefers that the key be the first column. Field is an interchangeable reference.

table, database
A table in the database. Because of the evolution of MiniVend from a single-table database to an access method for an unlimited number of tables (and databases, for that matter), we will sometimes refer to a table as a database. The only time database refers to something different is when describing that concept as it relates to SQL -- where a database contains a series of tables. MiniVend cannot create SQL databases, but given the proper permissions it may drop and create tables within that database.

If necessary, MiniVend reads the data to place in tables from standard.ASCII-delimited files. All of these ASCII source files are kept in the products directory, normally products in the catalog directory (where catalog.cfg is).

NOTE: Microsoft Excel is a widely-used tool to maintain MiniVend databases, but has several problems with its standard TAB-delimited export, like encasing fields containing commas in quotes, generating extra carriage returns embedded in records, and not including trailing blank fields. To avoid problems, use a text-qualifier of none.

The ASCII files can have ^M (carriage return) characters if desired, but must have a newline character at the end of the line to work -- Mac users uploading files must use ASCII mode, not binary mode!

MiniVend sets the default ASCII delimiter scheme with the Delimiter directive, which can have one of three settings, TAB, PIPE, or CSV.

IMPORTANT NOTE: The items must be separated by a single delimiter. The items are lined up for your reading convenience.

TAB
Fields separated by ^I characters. No whitespace should be at the beginning of the line.

code description price image SH543 Men's fine cotton shirt 14.95 shirts.jpg

PIPE
Fields separated by | characters. No whitespace should be at the beginning of the line.

code|description|price|image SH543|Men's fine cotton shirt|14.95|shirts.jpg

CSV
Fields enclosed in quotes, separated by commas. No whitespace should be at the beginning of the line.

"code","description","price","image" "SH543","Men's fine cotton shirt","14.95","shirts.jpg"

NOTE: Using the default TAB delimiter is highly recommended if you.are planning on searching the ASCII source file of the database. PIPE works fairly well, but CSV delimiter schemes cause problems with searching.

The Delimiter directive sets the default scheme, and should be set to one of those three values. TAB is the default scheme.

IMPORTANT NOTE: Field names are usually case-sensitive. Unless you are consistent in the names, you will have problems. All lower or all upper case names are recommended.

MiniVend uses one mandatory database, the products database. It is by default identified as products and the ASCII source is kept in the file products.asc in the products directory. This file is also the default file for searching with the THE SEARCH ENGINE .

MiniVend also has a number of standard but optional databases, some of which are in fixed special formats:

shipping.asc
The database of shipping options if the CustomShipping directive is in use. This is a fixed-format database, and must be created as specified. See SHIPPING .

salestax.asc
The database of sales tax information if the [salestax] tag is to be used. A default is supplied -- caution, these things change! This is a fixed-format database, and must be created as specified. See Sales Tax .

accessories.asc
A simple auxiliary database keyed on the product code. It's value is available via the [item_accessories] or [accessories code] tags. This is a fixed-format database, and must be created as specified. See Accessories . The big advantage of this database is speed -- it is always retained in memory. If you have a large number (many thousands) of items, use an Arbitrary Database instead.

pricing.asc
The database of quantity pricing information. It must be defined as the regular MiniVend database pricing, with the product code as the first field, and a field named price (all lower case) that holds space-separated price information in the order defined by PriceBreaks . Also subject to MixMatch . In addition, this database may hold information about price adjustments -- see PriceAdjustment . This is a database that can be in any form, including SQL/DBI if desired. The only requirement is the presence of the price field in the proper format, and an appropriate key.

.

The Product Database

Each product you are selling should be given a product code: A short code that identifies the product on the ordering page and in the catalog. You can use any combination of letters, digits, dashes, periods, hash signs, or underscores for the product code. The products.asc file is a ASCII-delimited list of all the product codes, along with an arbitrary number of fields which must contain at least the fields description and price (or whatever you set the PriceField and DescriptionField directives to). Any additional information you want in the catalog can be placed in any arbitrary field. See MiniVend Database Capabilityfor details on the format.

Field names are case-sensitive. Unless you have fields with the names ``description'' and ``price'' field, you will have to appropriately set the PriceField and DescriptionField directives to use the [item-price] and [item-description] tags.

The product code must be the first field in the line, and must be unique. Product codes can contain the characters A-Za-z0-9, along with hyphen (-), underscore (_), pound sign/hash mark (#), slash (/), and period (.).

The words should be separated by one of the approved delimiting schemes (TAB, PIPE, or CSV, set with the Delimiter directive), and are case-sensitive. If you play with the case of the ``description'' or ``price'' field, you will have to appropriately set the PriceField and DescriptionField directives.

NOTE: CSV is not recommended as the scheme for the products database. It is much slower than TAB- or PIPE-delimited, and dramatically reduces search engine functionality -- no field-specific searches are possible. Don't use it unless you know exactly what you are doing -- you will be sorry if you do. Using CSV for any small database that will not be searched is fine.

Arbitrary Databases

MiniVend can manage an unlimited number of arbitrary database tables. They are in the same format as the products file by default, but an unlimited number of addressable schemes are available. These are defined by default:

Type 1 DEFAULT - uses default delimiter set by Delimiter Type 2 LINE Each field on its own line, a blank line or lines separates the record. Watch those carriage returns! Type 3 %% Fields separated by a \n%%\n combination, records by \n%%%\n (where \n is a newline). Watch those carriage returns! Type 4 CSV Type 5 PIPE Type 6 TAB Type 7 mSQL Type 8 SQL

The databases are specified in Database directives, as:

Database Arbitrary arbitrary.csv CSV

That specifies a type 4 database, the ASCII version of which is located in the file arbitrary.csv, and the identifier it will be accessed under in MiniVend is ``Arbitrary''. The DBM file, if any, will be created in the same directory if the ASCII file is newer, or if the DBM file does not exist. The files will be created as arbitrary.db or arbitrary.gdbm, depending on DBM type.

The identifier is case sensitive, and can only contain characters in the class [A-Za-z0-9_]. Fields are accessed with the [item_data identifier field] or [data identifier field key] elements.

MiniVend built-in database support

If you specify one of the first 6 types, the database will automatically be built in the default MiniVend DB style. You cannot mix the styles -- all built-in databases on a single server will be the same style. They will coexist just fine with an unlimited number of DBI databases of different types.

In addition to the database, the session files will be kept in the default format, and are affected by the actions below.

The order of preference is:

GDBM
This uses the Perl GDBM_File module to build a GDBM database. You can see if GDBM is in your perl with the command:

perl -e 'require GDBM_File and print "I have GDBM.\n"'

Installing GDBM_File requires rebuilding Perl after obtaining the GNU GDBM package, and is beyond the scope of this forum. Linux will typically have this by default -- most other operating systems will need to specifically build this in.

DB_File (Berkeley DB)
This uses the DB_File module to build a Berkeley DB (hash) database. You can see if DB_File is in your perl with the command:

perl -e 'require DB_File and print "I have Berkeley DB.\n"'

Installing DB_File requires rebuilding Perl after obtaining the Berkeley DB package, and is beyond the scope of this document. BSDI, FreeBSD, and Linux will typically have it by default -- most other operating systems will need to specifically build this in.

If you wish to use DB_File even though you have GDBM_File in your Perl, you must set the environment variable MINIVEND_DBFILE to a true (non-zero, non-blank) value:

# csh or tcsh setenv MINIVEND_DBFILE 1 # sh, bash, or ksh MINIVEND_DBFILE=1 ; export MINIVEND_DBFILE

Then re-start the server.

In-memory
This uses Perl hashes to store the data directly in memory. Every time you restart the MiniVend server, it will re-import all in-memory databases for every catalog.

If you wish to use this despite the presence of GDBM_File or DB_File, set the environment variable MINIVEND_NODBM as above, then re-start the server.

.

Character usage restrictions

To review, database identifiers, field names, and product codes (database keys) are restricted in the characters they may use. A short table showing restrictions:

Legal characters --------------------- Database identifiers A-Z a-z 0-9 _ Field names A-Z a-z 0-9 _ # - . / Database keys (product code/SKU) A-Z a-z 0-9 _ # - . / Database values Any (subject to field/record delimiter)

You probably should restrict the field names to the same set of characters as database identifiers -- this will prevent conflict with external database programs, noticeably SQL databases which use the period (.) as a table.field separator.

Import Attributes

Especially in SQL databases, there are certain things that can be set with additional database attributes. For text import, the CONTINUE extended database import attribute allows additional control over the format of imported text.

NOTE: CONTINUE applies to all types except CSV.

CONTINUE
One of UNIX or DITTO. The default is to simply split the line/record according to the delimiter, with no possible spanning of records. Setting CONTINUE to UNIX appends the next line to the current when it encounters a backslash (\) at the end of a record, just like many Unix commands and shells.

DITTO is invoked when the key field is blank -- it adds the contents of following fields to the one above, separated by a newline character. This allows additional text to be added to a field beyond the 255 characters available with most spreadsheets and flat-file databaseses.

Example in catalog.cfg:

Database products products.asc TAB Database products CONTINUE DITTO

Products.asc file:

code price description 00-0011 500000 The Mona Lisa, one of the worlds great masterpieces. Now at a reduced price!

The description for product 00-0011 will contain the contents of the description field on both lines, separated by a newline.

NOTE: Fields are separated by tabs, formatted for reading convenience.

This will work for multiple fields in the same record. If the field contains any non-empty value, it will be appended.

.


SQL SUPPORT

MiniVend can use any of a number of SQL databases through the powerful Perl DBI/DBD access methods. No SQL database is included with MiniVend, but there are a number widely available on the net, and many are free for non-commercial use. Some examples include mSQL, mySQL, Solid, and Qbase.

It is beyond the scope of this document to describe SQL, mSQL, or DBI/DBD, and we will not attempt to. Sufficient familiarity is assumed.

In most cases, MiniVend cannot perform administrative functions like creating a database or setting access permissions. This must be done with the tools provided with your SQL distribution. But if given a blank database and the permission to read and write it, MiniVend can import ASCII files and bootstrap you from there.

Msql support

The first minimal SQL support provided by MiniVend was for the Msql.pm module. This is now deprecated in favor of the DBI support. In most cases, existing Msql users should be able to install and test DBD::mSQL, then change the database directive to the type of dbi:mSQL:minivend and go from there. You may have to set your directive to dbi:mSQL:minivend:localhost:1114 or some other value corresponding to host and TCP port.

SQL support via DBI

MiniVend now provides complete external SQL database support via the Perl DBI and DBD modules. This allow transparent access to any database that is supported by a DBD module. The current list includes mSQL, mySQL, Solid, Postgres, Oracle, Sybase, Informix, Ingres, Qbase, DB2, Fulcrum, and others. Any ODBC (with appropriate driver) should also be supported.

The configuration of the DBI database is done by setting attributes in additional Database directives after the initial defining line as described above. For example, the following defines the database arbitrary as a DBI database, sets the data source (DSN) to an appropriate value for an mSQL database named minivend on port 1114 of the local machine:

Database arbitrary arbitrary.asc SQL Database arbitrary DSN dbi:mSQL:minivend:localhost:1114

As a shorthand method, you can instead include the DSN as the type:

Database arbitrary arbitrary.asc dbi:mSQL:minivend:localhost:1114

Supported configuration attributes include (but are not limited to):

DSN
A specification of the DBI driver and its data source. To use the DBD::mSQL driver for DBI, you would typically use:

dbi:mSQL:minivend:othermachine.my.com:1112

where mSQL selects the driver (case IS important), minivend selects the database, othermachine.my.com selects the host, and 1112 is the port. On many systems, dbi:mSQL:minivend will work just fine. (The minivend database must already exist, of course.)

This is the same as the DBI_DSN environment variable -- if you don't set the DSN parameter, then the value of DBI_DSN will be used to try and find the proper database to connect to.

USER
The user name you log into the database with -- same as the environment variable DBI_USER. If you don't need a user name, just don't set the USER directive.

PASS
The password you log into the database with -- same as the environment variable DBI_PASS. If you don't need a password, just don't set the PASS directive.

COLUMN_DEF
A comma-separated set of lines in the form NAME=TYPE(N), where NAME is the name of the field/column, TYPE is the SQL data type reference, and N is the length (if needed). Most MiniVend fields should be of the fixed-length character type, something like char(128). In fact that is the default if you do not choose a type for a column. You can have as many lines as needed. This is not a DBI parameter, it is specific to MiniVend.

NAME
A space-separated field of column names for a table. Normally not used -- MiniVend should resolve the column names properly upon query. Set this if your catalog errors out with ``dbi: can't find field names'' or the like. The first field should always be code . This is not a DBI parameter, it is specific to MiniVend. All columns must be listed, in order of their position in the table.

NUMERIC
Tells MiniVend to not quote values for this field; allows numeric data types for SQL databases. Placed as a space-separated field of column names for a table, in no particular order. This must be defined if you are to use an numeric value, as DBI does not yet have standard type queries.

DELIMITER
A MiniVend delimiter type - one of TAB,CSV,PIPE,%%,LINE or the corresponding numeric type. It can also be a custom delimiter as specified with FieldDelimiter and RecordDelimiter . The default for SQL (and Msql) databases is TAB -- use DELIMITER if you wish to import another type. This is not a DBI parameter, it is specific to MiniVend.

KEY
You can change the keying default of code in the first column of the database with the KEY directive. Don't use this unless you know exactly what you are doing and are prepared to alter all searches, imports, and exports accordingly. It is best to just accept the default and make the first column the key for any MiniVend database.

ChopBlanks,LongReadLen,LongTruncOK,RaiseError, etc.
Sets the corresponding DBI attribute. Of particular interest is ChopBlanks, which should be set on drivers which by default return space-padded fixed-length character fields (Solid is an example).

The supported list as of release of MiniVend 3.02 is:

ChopBlanks CompatMode LongReadLen LongTruncOk PrintError RaiseError Warn

Issue the shell command perldoc DBI for more information.

Here is an example of a completely set up DBI database on mySQL, using.a comma-separated value input, setting the DBI attribute LongReadLen to retrieve an entire field, and changing some field definitions from the default char(128):

Database products products.csv dbi:mysql:minivend:localhost:3333 Database products USER mike Database products PASS NeVairBE Database products DELIMITER CSV # Set a DBI attribute Database products LongReadLen 128 # change some fields from the default field type of char(128) # Only applies if Minivend is importing from ASCII file # If you set a field to a numeric type, you must set the # NUMERIC attribute Database products COLUMN_DEF price=float, code=char(20) Database products COLUMN_DEF author=char(40), title=char(64) Database products COLUMN_DEF nontaxable=char(3) Database products NUMERIC price

You must have mySQL, DBI, and DBD::mysql completely installed and tested, and have created the database minivend for this to work. Permissions are difficult on mySQL -- if you have trouble, try starting the mySQL daemon with safe_mysqld --skip-grant-tables & for testing purposes.

To change to ODBC, the only changes required might be:

Database products DSN dbi:ODBC:TCP/IP localhost 1313 Database products ChopBlanks 1

The DSN setting is specific to your ODBC setup. The ChopBlanks setting takes care of the space-padding in Solid and some other databases -- it is not specific to ODBC. Once again, DBI, DBD::ODBC, and the and appropriate ODBC driver must be installed and tested.

SQL Access Methods

A MiniVend SQL database can be accessed with the same tags as any of the other databases can. In addition to those standard methods, direct SQL support is provided with the [sql function] TEXT [/sql identifier] tag set. The MiniVend database identifier only needs to be set if the table resides in a different database than the main products database -- if you don't use SQL for the products database you will ALWAYS need to set it.

For any of these, you may pass arguments with the [arg]argument[/arg] quoting method, which substitutes the contained value for successive values of %s in the query. For example:

[sql html] [arg][value passed_title][/arg] [arg][value passed_artist][/arg] select code, title, title from products where artist = %s and title = %s [/sql] * optional parameter SQL Any valid SQL query (usually a select)

[sql array] SQL [/sql identifier*]
A complete array of arrays, suitable for eval by Perl, can be returned by this query. This tag pair encloses any valid SQL query, and returns the results (if any) as a string representing rows and columns, in Perl array syntax. If placed in an embedded Perl area as:

[perl]
    my $string =<<'EOF';
 [sql array]select * from arbitrary where code <= '19'[/sql arbitrary]
 EOF
    my $ary = eval $string;
    my $out = '';
    my $i;
    foreach $i (@$ary) {
        $out .= $i->[0];
        $out .= "
"; } $out; [/perl]

NOTE: The 'EOF' string terminator must START the line, and not have trailing characters. DOS users, beware of carriage returns!

[sql hash] SQL [/sql identifier*]
A complete hash of hashes, suitable for eval by Perl, can be returned by this query. This tag pair encloses any valid SQL query, and returns the results (if any) as a string representing rows and columns, in Perl associative array, or hash, syntax. If placed in an embedded Perl area as:

[perl]
    my $string =<<'EOF';
 [sql hash]select * from arbitrary where code <= '19'[/sql]
 EOF
    my $hash = eval $string;
    my $out = '';
    my $key;
    foreach $key (keys %$hash) {
        $out .= $key->{field1};
        $out .= "
"; } $out; [/perl]

[sql set] SQL [/sql identifier*]
Any arbitrary SQL query can be passed with this method. No return text will be sent. This might be used for passing an order to an order database, perhaps on the order report or receipt page. An example might be:

[sql set] insert into orders values ('[value mv_order_number]', '[value name escape]', '[value address escape]', '[value city escape]', '[value state escape]', '[value zip escape]', '[value phone escape]', '[item-list] Item: [item-code] Quan: [item-quantity] Price: [item-price] [/item-list]' ) [/sql orders]

The values entered by the user are escaped, which prevents errors if quote characters have slipped into their entry.

[sql param] SQL [/sql]
A list of keys, or in fact any SQL fields, can be returned as a set of parameters suitable for passing to a program or list primitive. This tag pair encloses any valid SQL query, and returns the results (if any) as a series of space separated fields, enclosed in quotes. This folds the entire return into a single row, so it may be used as a list of keys.

[sql html] SQL [/sql]
This tag returns a set of HTML table rows with bold field names at the top, followed by each row in a set of table cells. The <TABLE> and </TABLE> tags are not supplied, so you can set your own border and shading options. Example:

<TABLE BORDER=2> [sql html]select * from arbitrary where code > '19' order by field2[/sql] </TABLE>

[sql list SQL] list [/sql]
This tag differs from the rest in that it passes the query enclosed inside the tag itself. The enclosed text is then evaluated with the same method as with a loop list, with data items (in columns) iterated over for the contents of a list. The following snippet will place a three-column list in an HTML table:

<TABLE BORDER=2> <TR><TH><B>SKU</B></TH><TH><B>Description</B></TH><TH><B>Price</B></TH> [sql list select * from arbitrary where code > '19' order by field2 ] <TR> <TD>[page [sql-code]][sql-code]</A></TD> <TD>[sql-param 1]</TD> <TD>[sql-param 2]</TD> </TR> [/sql] </TABLE>

It uses the same tags as in the [loop_list], except prefixed with sql. Available are the following, in order of interpolation:

[sql_param n] Field n of the returned query (in the row) [if_sql_field fld] Returns enclosed text only product field not empty [/if_sql_field] Terminator for above [if_sql_data db fld] Returns enclosed text only if data field not empty [/if_sql_field] Terminator for above [sql_increment] Returns integer count of row [sql_code] The first field of each row returned [sql_data db fld] Database field for [sql_code] [sql_description] Product description for [sql_code] [sql_field fld] Product field for [sql_code] [sql_link] Same as item-link [sql_price q*] Price for [sql_code], optional quantity q

.

Importing from an ASCII file

When importing a file for SQL, MiniVend by default uses the first column of the ASCII file as the primary key, with a char(16) type, and assigns all other columns a char (128) definition. These definitions can be changed by placing the proper definitions in COLUMN_DEF Database directive attribute:

Database products COLUMN_DEF price=char(20), nontaxable=char(3)

You can set this as many times as desired if it will not fit on the line nicely.

Database products COLUMN_DEF price=char(20), nontaxable=char(3) Database products COLUMN_DEF description=char(254)

To create an index automatically, you can append information when the value is in quotes:

Database products COLUMN_DEF "code=char(14) primary key"

The field delimiter to use is TAB by default, but can be changed with the Database DELIMITER directive:

Database products products.csv dbi:mSQL:minivend:localhost:1114 Database products DELIMITER CSV

If you wish to create other secondary keys to speed sorts and searches, you can either use MiniVend tags in an admin menu page

[sql set]CREATE INDEX CATEGORY_IDX on products (category)[/sql]

or use external database tools. Careful! Not all SQL databases use the same index commands. For example, with MySQL you would do instead:

[sql set]ALTER TABLE products CHANGE category category char(128) key[/set]

If you wish to use an existing SQL database instead of importing, set the NoImport directive in catalog.cfg to include any database identifiers you never wish to import:

NoImport products inventory

WARNING: If MiniVend has write permission on the products database, you must be careful to set the NoImport directive or create the proper .sql file. If that is not done, and the database source file is changed, the SQL database could be overwritten. In any case, always back up your database before enabling it for use by MiniVend.

Exporting from a database

To export your existing database to a file suitable for searching by MiniVend, you can create an AdminPage (or any page, for that matter) that contains a [tag export ...][/tag] element. For example, the following UNIX shell script will create a page only accessible to the AdminUser which will export the products database to the MiniVend default search file products.asc :

#!/bin/sh # Set the catalog directory. If you put this file in a # catalog template (like simple or sample), it should be set # up correctly. # # Example: # # CATDIR=/home/me/catalogs/simple # CATDIR=__MVC_CATROOT__ cd $CATDIR # make a directory mkdir pages/admin # protect it. If you have trouble with "VIOLATION", you can # remove the file temporarily. echo "protected" > pages/admin/.access
    # create the page.
    cat <<EOF > pages/admin/export.html
    <HTML><HEAD>
    <TITLE>Export products.asc</TITLE>
    </HEAD>
    <BODY>
    [if explicit ``[tag export products products.asc TAB][/tag]'']
    Exported OK!
    [else]
    <FONT COLOR=RED>Error on export:</FONT> [data session last_error]
    [/else]
    [/if]
    </BODY></HTML>
    EOF
    # Voila! Access with something like:
    #
    #     http://yourcatalog.com/cgi-bin/simple/admin/export

Perhaps a better method is to define the same sort of tags in an OrderProfile , and then use forms and buttons to access the profile.


MINIVEND TAG REFERENCE

To build complex order forms and reports, MiniVend has a complete tag language with over 80 different functions.

There is conditional capability with the [if ...] text [else] else-text [/else][/if] construct. It allows for testing for a condition within the Vend session, and if true, inserting text and/or HTML. If the condition is not true, no text (or the optional [else] text) will be inserted.

This facility cannot be considered a language, for constructs cannot be nested in a linear fashion, and operations cannot be performed (except as side effects to the [if] tag).

Most of the tests use Perl code, but MiniVend uses the Safe module with its default restrictions to help ensure that improper code will not crash the server or modify the wrong data. There is nothing to be done if your code enters an endless loop, though, and you have to use this capability with caution.

New and Old syntax

Starting with MiniVend 3.0, a new tag syntax becomes operational. It overcomes some of the limitations of MiniVend conditional HTML, and has sequential evaluation.

To use the new more regular syntax by default, set the NewTags directive to Yes. The demo catalog is distributed with NewTags Yes starting at MiniVend 3.07.

In most cases, tags specified in the old fashion will work the same in the new syntax. The only time you will need to modify them is when there is some ambiguity as to which parameter is which, or when you need to use the output of a tag as the attribute parameter for another tag.

With some exceptions ([if ....] [/if], [include] and [buttonbar ..] among them) the output of a tag will not be re-interpreted for MiniVend tag constructs. All tags accept the INTERPOLATE=1 tag modifier, which causes the interpretation to take place. It is frequent that you will not want to interpret the contents of a [set variable] TAGS [/set] pair, as that might contain tags which should only be upon evaluating an order profile, search profile, or mv_click operation. If you wish to perform the evaluation at the time a variable is set, you would use [set name=variable interpolate=1] TAGS [/set].

To use the new syntax only on a particular page, place one [new] tag in your page. Likewise, to use old syntax when new is the default, place one [old] tag in the page.

If you have regions of the page which work under the old syntax, you can surround them with [compat] [/compat] tag pair. This will evaluate that region only according to the old syntax.

NOTE WHEN USING OLD SYNTAX: MiniVend interpolates tags in a highly ordered fashion, with each tag having a precedence. The order of the tag interpolation can be changed by enclosing the tag in a set of double square brackets, bringing it forward in the process. The order of interpolation is:

tag [[ANY TAG]] cart item-list loop default value scratch calc if lookup set data msql|sql file finish_order frames_on frames_off framebase body help buttonbar random rotate checked selected accessories field pagetarget area areatarget page last_page perl order nitems discount subtotal shipping shipping_description salestax total_cost price currency description row process_order process_search process_target

DATA and FIELD

The [data ...] and [field ...] tags access elements of MiniVend databases. They are the form used outside of the iterating lists, and can be effecfively used to do lookups when the table, column/field or key/row is conditional based on a previous operation.

The following are equivalent for attribute names:

base ---> table --> database name ---> field --> column --> col code ---> key --> row

[data area field key ``value''* increment*]
(new syntax: [data base=``database'' field=``field'' key=``key'' value=``value'' op="increment] )

Returns the value of the field in any of the arbitrary databases, or from the variable namespaces. If the optional value is supplied, the database value will be changed to it -- no ] characters may be present in the value unless using the new tag style. If the option increment* is present, the field will be atomically incremented with the value in value .

If a DBM-based database is to be modified, it must be flagged writable on the page calling the write tag. Use [tag flag write]products[/tag] to mark the products database writable, for example.

In addition, the [data ...] tag can access a number of elements in the MiniVend session database:

accesses Accesses within the last 30 seconds arg The argument passed in a [page ...] or [area ...] tag browser The user browser string host MiniVend's idea of the host (modified by DomainTail) last_error The last error from the error logging last_url The current MiniVend path_info logged_in Whether the user is logged in (addon UserDB feature) pageCount Number of unique URLs generated prev_url The previous path_info referer HTTP_REFERER string ship_message The last error messages from shipping source Source of original entry to MiniVend time Time (seconds since Jan 1, 1970) of last access user The REMOTE_USER string username User name logged in as (addon UserDB feature)

Databases will hide variables, so don't name a database ``session'', ``scratch'', or any of the other reserved names or you won't be able to use the [data ...] tag to read them. Case is sensitive, so in a pinch you could call the database ``Session'', but it would be better not to.

[field name code]
(new syntax [field code=``code'' name=``fieldname''])

Expands into the value of the field name for the product identified by code as found by searching the products database. It will return the first entry found in the series of Product Files. the products database. If you want to constrain it to a particular database, use the [data base name code] tag.

.

SET and SCRATCH

Scratch variables are maintained in the user session separate from the form variable values set on HTML forms.

Many things can be controlled with scratch variables, notable search and order processing, the mv_click multiple variable setting facility, and key MiniVend conditions like whether an item will be ordered on a separate line.

There are two tags which are used to access the space, [set name]value[/set] and [scratch name].

[set variable]value[/set]
(new syntax [set name=``variable''] value [/set])

Sets a scratchpad variable to value .

Most of the mv_* variables that are used for search and order conditionals are in another namespace -- they can be set by means of hidden fields in a form.

You can set an order profile with:

[set checkout] name=required address=required [/set] <INPUT TYPE=hidden NAME=mv_order_profile VALUE="checkout">

A search profile would be set with:

[set substring_case] mv_substring_match=yes mv_case=yes [/set] <INPUT TYPE=hidden NAME=mv_profile VALUE="substring_case">

[scratch name]
Returns the contents of a scratch variable to the page.

[if scratch name op* compare*] .... [/if]
Tests a scratch variable (see IF ).

.

LOOP and TAG EACH

Loop lists can be used to construct arbitrary lists based on the contents of a database field or other value. The [tag each table] [/tag] construct uses the same interior tags, but iterates over every key of a particular database table.

Both can be sorted with [sort table:field:mod -start +number] modifiers. See SORTING .

[loop item item item] LIST [/loop]
(new syntax: [loop with=``-a''* arg=``item item item''])

Returns a string consisting of the LIST, repeated for every item in a comma-separated or space-separated list. Operates in the same fashion as the [item-list] tag, except for order-item-specific values. Intended to pull multiple attributes from an item modifier -- but can be useful for other things, like building a pre-ordained product list on a page.

Loop lists can be nested reliably in MiniVend 3.06 by using the with=``tag'' parameter. New syntax:

[loop arg="A B C"] [loop with="-a" arg="[loop-code]1 [loop-code]2 [loop-code]3"] [loop with="-b" arg="X Y Z"] [loop-code-a]-[loop-code-b] [/loop] [/loop] [/loop]

An example in the old syntax:

[compat] [loop 1 2 3] [loop-a 1 2 3 ] [loop-b 1 2 3] [loop-code].[loop-code-a].[loop-code-b] [/loop-b] [/loop-a] [/loop] [/compat]

All loop items in the inner loop-a loop need to have the with value appended, i.e. [loop-field-a name], [loop-price-a], etc. Nesting is arbitrarily large, though it will be slow for many levels.

[if_loop_data table field] IF [else] ELSE [/else][/if_loop_field]
Outputs the IF if the field in table is non-empty, and the ELSE (if any) otherwise.

[if_loop_field field] IF [else] ELSE [/else][/if_loop_field]
Outputs the IF if the field in the products table is non-empty, and the ELSE (if any) otherwise.

[loop_accessories]
Evaluates to the value of the Accessories database entry for the item.

[loop_change marker]
Same as [on_change] but within loop lists.

[loop_code]
Evaluates to the product code for the current item.

[loop_data database fieldname]
Evaluates to the field name fieldname in the arbitrary database table database , for the current item.

[loop_description]
Evaluates to the product description (from the products file) for the current item.

[loop_field fieldname]
Evaluates to the field name fieldname in the database, for the current item.

[loop_increment]
Evaluates to the number of the item in the list. Used for numbering items in the list.

[loop_last]tags[/loop_last]
Evaluates the output of the MiniVend tags encased inside, and if it evaluates to a numerical non-zero number (i.e. 1, 23, or -1) then the loop iteration will terminate. If the evaluated number is negative, then the item itself will be skipped. If the evaluated number is positive, then the item itself will be shown but will be last on the list.

[loop-last][calc] return -1 if '[loop-field weight]' eq ''; return 1 if '[loop-field weight]' < 1; return 0; [/calc][/loop-last]

If this is contained in your [loop list] and the weight field is empty, then a numerical -1 will be output from the [calc][/calc] tags; the list will end and the item will not be shown. If the product's weight field is less than 1, a numerical 1 is output. The item will be shown, but will be the last item shown.

[loop_next]tags[/loop_next]
Evaluates the output of the MiniVend tags encased inside, and if it evaluates to a numerical non-zero number (i.e. 1, 23, or -1) then the loop will be skipped with no output. Example:

[loop-next][calc][loop-field weight] < 1[/calc][/loop-next]

If this is contained in your [loop list] and the product's weight field is less than 1, then a numerical 1 will be output from the [calc][/calc] operation. The item will not be shown.

[loop_price n*]
Evaluates to the price for optional quantity n (from the products file) of the current item.

.

IF

[if type field op* compare*]
(new syntax [if type=``type'' term=``field'' op=``op'' compare=``compare''])

[if !type field op* compare*]
(new syntax [if type=``!type'' term=``field'' op=``op'' compare=``compare''])

Allows conditional building of HTML based on the setting of various MiniVend.session and database values. The general form is:

[if type term op compare] [then] If true, this is printed on the document. The [then] [/then] is optional in most cases. If ! is prepended to the type setting, the sense is reversed and this will be output for a false condition. [/then] [elsif type term op compare] Optional, tested when if fails [/elsif] [else] Optional, printed when all above fail [/else] [/if]

The [if] tag can also have some variants:

[if explicit][condition] CODE [/condition] Displayed if valid Perl CODE returns a true value. [/if]

You can do some Perl-style regular expressions:

[if value name =~ /^mike/] This is the if with Mike. [elsif value name =~ /^sally/] This is an elsif with Sally. [/elsif] [elsif value name =~ /^pat/] This is an elsif with Pat. [/elsif] [else] This is the else, no name I know. [/else] [/if]

While the new tag syntax works for [if ...], it is more convenient to use the old in most cases. It will work fine with both parsers. The only exception is if you are planning on doing a test on the results of another tag sequence: [if value name =~ /[value b_name]/] Shipping name matches billing name. [/if]

Oops! This will not work with the new parser. You must do instead

[compat] [if value name =~ /[value b_name]/] Shipping name matches billing name. [/if] [/compat]

or

[if type=value term=name op="=~" compare="/[value b_name]/"] Shipping name matches billing name. [/if]

The latter has the advantage of working with any tag:

[if type=value term=high_water op="<" compare="[shipping]"] Shipping cost is too high, charter a truck. [/if]

If you wish to do AND and OR operations, you will have to use [if explicit]. This allows complex testing and parsing of values.

There are many test targets available:

config Directive
The MiniVend configuration variables. These are set by the directives in your MiniVend configuration file (or the defaults).

[if config CreditCardAuto] Auto credit card validation is enabled. [/if]

data database::field::key
The MiniVend databases. Retrieves a field in the database and returns true or false based on the value.

[if data products::size::99-102] There is size information. [else] No size information. [/else] [/if] [if data products::size::99-102 =~ /small/i] There is a small size available. [else] No small size available. [/else] [/if]

discount
Checks to see if a discount is present for an item.

[if discount 99-102] Item is discounted. [/if]

explicit
A test for an explicit value. If perl code is placed between a [condition] [/condition] tag pair, it will be used to make the comparison. Arguments can be passed to import data from user space, just as with the [perl] tag.

[if explicit] [condition] $country = '[value country]'; return 1 if $country =~ /u\.?s\.?a?/i; return 0; [/condition] You have indicated a US address. [else] You have indicated a non-US address. [/else] [/if]

This example is a bit contrived, as the same thing could be accomplished with [if value country =~ /u\.?s\.?a?/i], but you will run into many situations where it is useful.

This will work for Variable values:

[if explicit "__MYVAR__"] .. [/if]

file
Tests for existence of a file. Useful for placing image tags only if the image is present.

[if file /home/user/www/images/[item-code].gif] <IMG SRC="[item-code].gif"> [/if]

items
The MiniVend shopping carts. If not specified, the cart used is the main cart. Usually used as a litmus test to see if anything is in the cart, for example:

[if items]You have items in your shopping cart.[/if] [if items layaway]You have items on layaway.[/if]

ordered
Order status of individual items in the MiniVend shopping carts. If not specified, the cart used is the main cart. The following items refer to a part number of 99-102.

[if ordered 99-102] ... [/if] Checks the status of an item on order, true if item 99-102 is in the main cart. [if ordered 99-102 layaway] ... [/if] Checks the status of an item on order, true if item 99-102 is in the layaway cart. [if ordered 99-102 main size] ... [/if] Checks the status of an item on order in the main cart, true if it has a size attribute. [if ordered 99-102 main size =~ /large/i] ... [/if] Checks the status of an item on order in the main cart, true if it has a size attribute containing 'large'. THE CART NAME IS REQUIRED IN THE OLD SYNTAX. The new syntax for that one would be: [if type=ordered term="99-102" compare="size =~ /large/i"] To make sure it is exactly large, you could use: [if ordered 99-102 main size eq 'large'] ... [/if] [if ordered 99-102 main lines] ... [/if] Special case -- counts the lines that the item code is present on. (Only useful, of course, when mv_separate_items or SeparateItems is defined.)

salestax
The salestax database.

[if salestax [value state] > 0] There is salestax for your state. [else] No salestax for your state. [/else] [/if]

Key matching is case-insensitive.

scratch
The MiniVend scratchpad variables, which can be set with the [set name]value[/set] element.

[if scratch mv_separate_items] Ordered items will be placed on a separate line. [else] Ordered items will be placed on the same line. [/else] [/if]

session
The MiniVend session variables. Of particular interest are login, frames , secure, and browser .

shipping
The shipping database.

validcc
A special case, takes the form [if validcc no type exp_date]. Evaluates to true if the supplied credit card number, type of card, and expiration date pass a validity test. Does a LUHN-10 calculation to weed out typos or phony card numbers.

value
The MiniVend user variables, typically set in search, control, or order forms. Variables beginning with mv_ are MiniVend special values, and should be tested/used with caution.

The field term is the specifier for that area. For example, [if session.frames] would return true if the frames session parameter was set.

As an example, consider buttonbars for frame-based setups. It would be nice to display a different buttonbar (with no frame targets) for sessions that are not using frames:

[if session frames] [buttonbar 1] [else] [buttonbar 2] [/else] [/if]

Another example might be the when search matches are displayed. If you use the string '[value mv_match_count] titles found', it will display a plural for only one match. Use:

[if value mv_match_count != 1] [value mv_match_count] matches found. [else] Only one match was found. [/else] [/if]

The op term is the compare operation to be used. Compare operations are as in Perl:

== numeric equivalence eq string equivalence > numeric greater-than gt string greater-than < numeric less-than lt string less-than != numeric non-equivalence ne string equivalence

Any simple perl test can be used, including some limited regex matching. More complex tests are best done with [if explicit].

[then] text [/then]
This is optional if you are not nesting if conditions, as the text immediately following the [if ..] tag is used as the conditionally substituted text. If nesting [if ...] tags you should use a [then][/then] on any outside conditions to ensure proper interoplation.

[elsif type field op* compare*]
(new syntax [elsif type=``type'' term=``field'' op=``op'' compare=``compare''])

Additional conditions for test, applied if the initial [if ..] test fails.

[else] text [/else]
The optional else-text for an if or if_field conditional.

[condition] text [/condition]
Only used with the [if explicit] tag. Allows an arbitrary expression in Perl to be placed inside, with its return value interpreted as the result of the test. If arguments are added to [if explicit args], those will be passed as arguments are in the [perl] construct.

[/if]
Terminates an if conditional.

.

TAG -- the catchall

Many MiniVend functions can be controlled or specified with [tag ...][/tag] pairs.

[tag arg* arg*]text[/tag]
Performs any of a number of operations, based on the presence of arg . The arguments that may be given are:

each database
Returns a loop-list with every key in database evaluated as the [loop-code]. This will return the key and field name for every record in the products database:

[tag each products][loop-code] [loop-field name]<BR>[/tag]

export database file* type*
Exports a complete MiniVend database to its text source file (or any specified file). The integer n, if specified, will select export in one of the enumerated MiniVend export formats. The following tag will export the products database to products.txt (or whatever you have defined its source file as), in the format specified by the Database directive:

[tag export products][/tag]

Same thing, except to the file products/new_products.txt:

[tag export products products/newproducts.txt][/tag]

Same thing, except the export is done with a PIPE delimiter:

[tag export products products/newproducts.txt 5][/tag]

The file is relative to the catalog directory, and only may be an absolute path name if NoAbsolute is set to No.

flag arg
Sets a MiniVend condition.

The following enables writes on the products and sizes databases held in MiniVend internal DBM format:

[tag flag write]products sizes[/tag]

SQL databases are always writable if allowed by the SQL database itself -- in-memory databases will never be written.

The [tag flag build][/tag] combination forces static build of a page, even if dynamic elements are contained. Similarly, the [tag flag cache][/tag] forces search or page caching (not usually wise).

log dir/file
Logs a message to a file, fully interpolated for MiniVend tags. The following tag will send every item code and description in the user's shopping cart to the file logs/transactions.txt:

[tag log logs/transactions.txt] [item_list][item-code] [item-description] [/item_list][/tag]

The file is relative to the catalog directory, and only may be an absolute path name if NoAbsolute is set to No.

mime description_string
Returns a MIME-encapsulated message with the boundary as employed in the other mime tags, and the description_string used as the Content-Description. For example

[tag mime My Plain Text]Your message here.[/tag]

will return

Content-Type: TEXT/PLAIN; CHARSET=US-ASCII Content-ID: [sequential, lead as in mime boundary] Content-Description: My Plain Text Your message here.

When used in concert with [tag mime boundary], [tag mime header], and [tag mime id], allows MIME attachments to be included -- typically with PGP-encrypted credit card numbers. See the demo page ord/receipt.html for an example.

mime boundary
Returns a MIME message boundary with unique string keyed on session ID, page count, and time.

mime header
Returns a MIME message header with the proper boundary for that session ID, page count, and time.

mime id
Returns a MIME message id with the proper boundary for that session ID, page count, and time.

[tag scan/options]encased text[/tag]
Builds a one-click search based on the enclosed text. Properly translates whitespace and non-word characters to be parseable by MiniVend. You can add the normal scan options, just the se=searchtext parameter will be affected. These two sequences evaluate the same:

[tag scan/sf=category]Renaissance[/tag] [page scan/sf=category/se=Renaissance]Renaissance[/page]

Where it is useful is in adding long strings that would otherwise be difficult to encode, like

[tag scan/sf=author/os=yes]John F. Kennedy[/tag]

instead of:

[page scan/sf=author/se=John%20F.%20Kennedy]John F. Kennedy[/page]

show_tags
The encased text will not be substituted for with MiniVend tags, with < and [ characters changed to &#lt; and &#91; respectively.

[tag show_tags][value whatever][/tag]

time
Formats the current time according to POSIX strftime arguments. The following is the string for Thursday, April 30, 1997.

[tag time]%A, %B %d, %Y[/tag]

touch
Touches a database to allow use of the tag_data() routine in user-defined subroutines. If this is not done, the routine will error out if the database has not previously been accessed on the page.

[tag touch products][/tag]

.

[comment] code [/comment]
Comments out MiniVend tags (and anything else) from a page. The contents are not displayed unless DisplayComments is set in minivend.cfg. Can be nested.

[perl args] code [/perl]
See the section on Embedded Perl Code .

.

User-defined Tags

MiniVend 3.04 allows the definition of user tags when using the new parsed HTML syntax (a [new] tag is on the page). They will not work with the old syntax. 3.06 adds the tags on a server-wide basis.

To define a tag that is catalog-specific, place UserTag directives in your catalog.cfg file. For server-wide tags, define them in minivend.cfg. Catalog-specific tags take precedence if both are defined. The directive takes the form:

UserTag tagname property value

where tagname is the name of the tag, property is the attribute (described below), and value is the value of the property for that tagname.

The user tags can either be based on Perl subroutines or just be aliases for existing tags. Some quick examples are below.

An alias:

UserTag product_name Alias data products title

This will change [product_name 99-102] into [data products title 99-102], which will output the title database field for product code 99-102. Don't use this with [item-data ...] and [item-field ...], as they are parsed separately. You could do [product-name [item-code]], though.

A simple subroutine:

UserTag company_name Routine sub { "Your company name" } When you place a [company-name] tag in a MiniVend page, the text C<Your company name> will be substituted.

A subroutine with a passed text as an argument:

UserTag caps Routine sub { return "\U@_" } UserTag caps HasEndTag

The tag [caps]This text should be all upper case[/caps] will become THIS TEXT SHOULD BE ALL UPPER CASE.

Here is a useful one you might wish to use:

    UserTag quick_table HasEndTag
    UserTag quick_table Interpolate
    UserTag quick_table Order   border
    UserTag quick_table Routine <<EOF
    sub {
        my ($border,$input) = @_;
        $border = `` BORDER=$border'' if $border;
        my $out = ``<TABLE ALIGN=LEFT$border>'';
        my @rows = split /\n+/, $input;
        my ($left, $right);
        for(@rows) {
            $out .= '<TR><TD ALIGN=RIGHT VALIGN=TOP>';
            ($left, $right) = split /\s*:\s*/, $_, 2;
            $out .= '<B>' unless $left =~ /</;
            $out .= $left;
            $out .= '</B>' unless $left =~ /</;
            $out .= '</TD><TD VALIGN=TOP>';
            $out .= $right;
            $out .= '</TD></TR>';
            $out .= ``\n'';
        }
        $out .= '</TABLE>';
    }
    EOF

Called with:

[quick-table border=2] Name: [value name] City: [value city][if value state], [value state][/if] [value country] [/quick_table]

The properties for UserTag are are:

Alias
An alias for an existing (or other user-defined) tag. It takes the form:

UserTag tagname Alias tag to insert

An Alias is the only property that does not require a Routine to process the tag.

CanNest
Notifies MiniVend that this tag must be checked for nesting. Only applies to tags that have HasEndTag defined, of course. NOTE: Your routine must handle the subtleties of nesting, so don't use this unless you are quite conversant with parsing routines. See the routines tag_loop_list and tag_if in lib/Vend/Interpolate.pm for an example of a nesting tag.

UserTag tagname CanNest

HasEndTag
Defines an ending [/tag] to encapsulate your text -- the text in between the beginning [tagname] and ending [/tagname] will be the last argument sent to the defined subroutine.

UserTag tagname HasEndTag

Interpolate
If this is defined, the resulting HTML from this tag will be re-parsed for more MiniVend tags.

UserTag tagname Interpolate

InvalidateCache
If this is defined, the presence of the tag on a page will prevent search cache, page cache, and static builds from operating on the page.

UserTag tagname InvalidateCache

Order
The optional arguments that can be sent to the tag. This defines not only the order in which they will be passed to Routine , but the name of the tags. If encapsulated text is appropriate ( HasEndTag is set), it will be the last argument.

UserTag tagname Order param1 param2

PosRoutine
Identical to the Routine argument -- a subroutine that will be called when the new syntax is not used for the call, i.e. [usertag argument] instead of [usertag ARG=argument]. If not defined, Routine is used, and MiniVend will usually do the right thing.

Routine
An inline subroutine that will be used to process the arguments of the tag. It must not be named, and will be allowed to access unsafe elements only if the minivend.cfg parameter AllowGlobal is set for the catalog.

UserTag tagname Routine sub { "your perl code here!" }

The routine may use a ``here'' document for readability:

    UserTag tagname Routine <<EOF
    sub {
        my ($param1, $param2, $text) = @_;
        return ``Parameter 1 is $param1, Parameter 2 is $param2'';
    }
    EOF

The usual here documents caveats apply.

Parameters defined with the Order property will be sent to the routine first, followed by any encapsulated text ( HasEndTag is set).

Note that the UserTag facility, combined with AllowGlobal, allows the.user to define tags just as powerful as the standard MiniVend tags. This is not recommended for the novice, though -- keep it simple. 8-)

PRICE, DESCRIPTION, ACCESSORIES

[price code quantity* database*]
(new syntax [price code=``code'' quantity=``quantity'' base=``database''])

Expands into the price of the product identified by code as found in the products database. If there is more than one products file defined, they will be searched in order unless constrained by the optional argument base. The optional argument quantity selects an entry from the quantity price list.

[description code database*]
(new syntax [description code=``code'' base=``database''])

Expands into the description of the product identified by code as found in the products database. If there is more than one products file defined, they will be searched in order unless constrained by the optional argument base.

[accessories code attribute*, type*, field*, database*, name*]
(new syntax [accessories code=``code'' arg="attribute*, type*, field*, database*, name*])

If not given one of the optional arguments, expands into the value of the accessories database entry for the product identified by code as found in the products database.

If passed any of the optional arguments, initiates special processing of item attributes based on entries in the product database.

attribute The item attribute as specified in the UseModifier configuration directive. Typical are "size" or "color". NOTE: You may not use the following names for attributes: item group quantity code mv_ib mv_mi mv_si type The action to be taken. The default is 'select', which builds an HTML select form entry for the attribute. Also recognized are 'multiple', which builds a multiple select box, and 'list', which simply lists the possible values. field The database field name to be used to build the entry (usually a select form field). Defaults to a field named the same as the attribute. database The database to find B<field> in, defaults to the first products file where the item code is found. name Name of the form variable to use if a form is being built. Defaults to mv_order_B<attribute> -- i.e. if the attribute is B<size>, the form variable will be named B<mv_order_size>.

When called with an attribute, the database is consulted and looks for a comma-separated list of attribute options. They take the form:

name=Label Text, name=Label Text*

The label text is optional -- if none is given, the name will be used.

If an asterisk is the last character of the label text, the item is the default selection. If no default is specified, the first will be the default. An example:

[accessories TK112 color]

This will search the product database for a field named ``color''. If an entry ``beige=Almond, gold=Harvest Gold, White*, green=Avocado'' is found, a select box like this will be built:

<SELECT NAME="mv_order_color"> <OPTION VALUE="beige">Almond <OPTION VALUE="gold">Harvest Gold <OPTION SELECTED>White <OPTION VALUE="green">Avocado </SELECT>

In combination with the mv_order_item and mv_order_quantity variables this can be used to allow entry of an attribute at time of order.

.

FILE and INCLUDE

These elements read a file from the disk and insert the contents in the location of the tag. [include ...] will allow insertion of MiniVend variables.

[file name]
(new syntax [file name=``name''])

Inserts the contents of the named file. The file should normally be relative to the catalog directory -- file names beginning with / or .. are only allowed if the MiniVend server administrator has disabled NoAbsolute .

[include file]
(new syntax [include file=``name''])

NOTE: New to MiniVend 3.04.

Same as [file name] except interpolates for all MiniVend tags and variables.

.

BODY, BUTTONBAR, RANDOM, ROTATE

Tags to help manage page appearance and advertising links:

[body n]
(new syntax [body type=``n''])

Selects from the predefined color schemes and/or backgrounds, and just becomes a <BODY> tag if none are defined. See Controlling Page Appearance.

[buttonbar n]
(new syntax [buttonbar type=``n''])

Selects from the predefined buttonbars, and is stripped if it doesn't exist. See Controlling Page Appearance.

[random]
Selects from the predefined random messages, and is stripped if none exist. See Controlling Page Appearance.

[rotate ceiling* floor*]
(new syntax [rotate floor=``n'' ceiling=``n''])

Selects from the predefined rotating banner messages, and is stripped if none exist. The optional ceiling sets the highest number that will be selected -- likewise floor sets the lowest. The default is to sequence through all defined rotating banners. Each user has a separate rotation pattern. See Controlling Page Appearance.

.

Tags for summarizing shopping basket/cart

The following elements are used to access common items which need to be displayed on baskets and checkout pages.

* marks an optional parameter

[item_list cart*]
(new syntax [item_list name=``cart''])

Places an iterative list of the items in the specified shopping cart, the main cart by default. See Item Lists for a description.

[/item_list]
Terminates the [item_list] tag.

[value field flag*]
Expands into the current value of the customer input field named by field. If flag is present, single and double quotes will be escaped with a backslash; this allows reliable SQL inserts. See the section on input fields for more information.

[nitems cart*]
Expands into the total number of items ordered so far. Takes an optional cart name as a parameter.

[subtotal]
Expands into the subtotal cost, exclusive of sales tax, of all the items ordered so far.

[salestax cart*]
Expands into the sales tax on the subtotal of all the items ordered so far. If there is no key field to derive the proper percentage, such as state or zip code, it is set to 0. See Sales Tax for more information.

[shipping_description mode*]
(new syntax [shipping_description name=``mode''])

The text description of mode -- the default is the shipping mode currently selected.

[shipping mode*]
(new syntax [shipping name=``mode''])

The shipping cost of the items in the basket via mode -- the default mode is the shipping mode currently selected in the mv_shipmode variable. See SHIPPING .

[total_cost cart*]
Expands into the total cost of all the items in the current shopping cart, including sales tax (if any).

[calc]
Starts a region where the arguments are calculated according to normal arithmetic symbols. For instance:

[calc] 2 + 2 [/calc]

will display:

4

[/calc]
Terminates the calculated region.

TIP: The [calc] tag is really the same as the [perl] tag, except that it doesn't accept arguments, is more efficient to parse, and is interpolated at a higher precedence.

[currency]
When passed a value of a single number, formats it according to the currency specification. For instance:

[currency]4[/currency]

will display:

4.00

Uses the Locale , PriceDivide , and PriceCommas settings as appropriate, and can contain a [calc] region. If Locale is set to pt, and PriceDivide to 100, the following

[currency] [calc] 50000 + 100000 [/calc] [/currency]

the number 1.500,00 will be displayed.

[/currency]
Terminates the currency region.

[cart name]
(new syntax [cart name=``name''])

Sets the name of the current shopping cart for display of shipping, price, total, subtotal, and nitems tags. If you wish to use a different price for the cart, all of the above except [shipping] will reflect the normal price field. You must emulate those operations with embedded Perl or the [item-list], [calc], and [currency] tags, or use the PriceAdjustment feature to set it.

[row nn]
(new syntax [row width=``nn''])

Formats text in tables. Intended for use in emailed reports or <PRE></PRE> HTML areas. The parameter nn gives the number of columns to use. Inside the row tag, [col param=value ...] tags may be used.

[/row]
Terminates a [row nn] element.

[col width=nn wrap=yes|no gutter=n align=left|right|input spacing=n]
Sets up a column for use in a [row]. This parameter can only be contained inside a [row nn] [/row] tag pair. Any number of columns (that fit within the size of the row) can be defined.

The parameters are:

width=nn The column width, I<including the gutter>. Must be supplied, there is no default. A shorthand method is to just supply the number as the I<first> parameter, as in [col 20]. gutter=n The number of spaces used to separate the column (on the right-hand side) from the next. Default is 2. spacing=n The line spacing used for wrapped text. Default is 1, or single-spaced. wrap=(yes|no) Determines whether text that is greater in length than the column width will be wrapped to the next line. Default is I<yes>. align=(L|R|I) Determines whether text is aligned to the left (the default), the right, or in a way that might display an HTML text input field correctly.

[/col]
Terminates the column field.

.

Item Lists

Within any page, the [item_list cart*] element shows a list of all the items ordered by the customer so far. It works by repeating the source between [item_list] and [/item_list] once for each item ordered. Between the item_list markers the following elements will return information for the current item:

[if_data table column]
If the database field column in table table is non-blank, the following text up to the [/if_data] tag is substituted. This can be used to substitute IMG or other tags only if the corresponding source item is present. Also accepts a [else]else text[/else] pair for the opposite condition.

[if_data ! table column]
Reverses sense for [if-data].

[/if_data]
Terminates an [if_data table column] element.

[if_field fieldname]
If the products database field fieldname is non-blank, the following text up to the [/if_field] tag is substituted. If you have more than one products database table (see ProductFiles), it will check them in order until a matching key is found. This can be used to substitute IMG or other tags only if the corresponding source item is present. Also accepts a [else]else text[/else] pair for the opposite condition.

[if_field ! fieldname]
Reverses sense for [if-field].

[/if_field]
Terminates an [if_field fieldname] element.

[item_accessories attribute*, type*, field*, database*, name*]
Evaluates to the value of the Accessories database entry for the item. If passed any of the optional arguments, initiates special processing of item attributes based on entries in the product database.

[item_code]
Evaluates to the product code for the current item.

[item_data database fieldname]
Evaluates to the field name fieldname in the arbitrary database table database , for the current item.

[item_description]
Evaluates to the product description (from the products file) for the current item.

[item_field fieldname]
Evaluates to the field name fieldname in the database, for the current item.

[item_increment]
Evaluates to the number of the item in the match list. Used for numbering search matches or order items in the list.

[item_last]tags[/item_last]
Evaluates the output of the MiniVend tags encased inside the tags, and if it evaluates to a numerical non-zero number (i.e. 1, 23, or -1) then the list iteration will terminate. If the evaluated number is negative, then the item itself will be skipped. If the evaluated number is positive, then the item itself will be shown but will be last on the list.

[item-last][calc] return -1 if '[item-field weight]' eq ''; return 1 if '[item-field weight]' < 1; return 0; [/calc][/item-last]

If this is contained in your [item-list] (or [search-list] or flypage) and the weight field is empty, then a numerical -1 will be output from the [calc][/calc] tags; the list will end and the item will not be shown. If the product's weight field is less than 1, a numerical 1 is output. The item will be shown, but will be the last item shown. (If it is an [item-list], any price for the item will still be added to the subtotal.)

[item_modifier attribute]
Evaluates to the modifier value of attribute for the current item.

[item_next]tags[/item_next]
Evaluates the output of the MiniVend tags encased inside, and if it evaluates to a numerical non-zero number (i.e. 1, 23, or -1) then the item will be skipped with no output. Example:

[item-next][calc][item-field weight] < 1[/calc][/item-next]

If this is contained in your [item-list] (or [search-list] or flypage) and the product's weight field is less than 1, then a numerical 1 will be output from the [calc][/calc] operation. The item will not be shown. (If it is an [item-list], any price for the item will still be added to the subtotal.)

[item_price n*]
Evaluates to the price for quantity n (from the products file) of the current item.

[discount_price n*]
Evaluates to the discount price for quantity n (from the products file) of the current item. Returns regular price if not discounted.

[item_discount]
Returns the difference between the regular price and the discounted price.

[item_quantity]
Evaluates to the quantity ordered for the current item.

[item_subtotal]
Evaluates to the subtotal (quantity * price) for the current item. Quantity price breaks are taken into account.

[modifier_name attribute]
Evaluates to the name to give an input box in which the customer can specify the modifier to the ordered item.

[quantity_name]
Evaluates to the name to give an input box in which the customer can enter the quantity to order.

.

Embedded Perl Code

Perl code can be directly embedded in MiniVend pages. The code is specified as [perl arguments*] any_legal_perl_code [/perl]. The value returned by the code will be inserted on the page.

(new syntax [perl arg=``arguments''* interpolate=1*])

Using MiniVend variables with embedded Perl capability is not recommended unless you are thoroughly familiar with Perl 5 references. You can insert Minivend tags inside the Perl code, though when using the new syntax, you will need to pass an INTERPOLATE=1 parameter to have tags inside [perl] and [/perl] interpreted. (In the old syntax, most tags are evaluated before [perl], though there are exceptions.)

More often you will want to use the tag access routine &safe_tag, which takes the tag name and any arguments as parameters. This has the advantage of only performing the operation when the code is executed. (A few tags can't be used with safe_tag, notably ones accessing a database that has not previously been accessed on the page.)

Examples:

# Simple example, old syntax [perl] $comments = '[value comments]'; [/perl] # New syntax # If the item might contain a single quote [perl interpolate=1] $comments = '[value comments escaped]'; [/perl] # Another method to avoid escape problems $comments = q{[value comments]}; # Works with all, only executed if code is reached $comments = safe_tag('value', 'comments');

This allows you to pass user-space variables for most needed operations. You can pass whole lists of items with constructs like:

# Perl ignores the trailing comma my(%prices) = ( [item_list] '[item_code]', '[item-price]', [/item_list]);

Even easier is the definition of a subroutine:

[set Thanks] my($name, $number) = @_; "Thanks, $name, for your order! The order number is $number.\n"; [/set] # New syntax [perl arg=sub interpolate=1] Thanks ('[value name escaped]', '[value mv_order_number escaped]') [/perl] # Old syntax, depends on [value ...] interpolated before [perl] [perl sub] Thanks ('[value name escaped]', '[value mv_order_number escaped]') [/perl]

(The escaped causes any single quotes which might be contained in the values to be escaped, preventing syntax errors in the case of a name like ``O'Reilly''.)

The arguments that can be passed are any to all of:

browser
The browser string from the users browser, read-only. Referred to in your code as $Safe{browser}.

carts
Gives read-write access to all of the shopping carts. on order. This is an array of hashes, and includes the product code, quantity, and any modifiers you have specified. Referred to in your code as a reference to the array, $Safe{items} or @{$Safe{items}}.

# Move contents of 'layaway' cart to main cart $Safe{carts}->{main} = $Safe{carts}->{layaway}; $Safe{carts}->{main} = [];

Careful with this -- you can lose the items on order with improper code, though syntax errors will be caught before the code is run.

cgi
Gives read-only access to the actual variables that were passed in the current CGI session. This is useful for testing what the user actually placed on the form, not just what MiniVend placed in the session. Called with

# Set if the user had a value for name in the *current* form $name = $Safe{'cgi'}->{name};

config
Gives read-write access to the configuration of the catalog. USE WITH EXTREME CAUTION -- many of the variables are references to anonymous arrays and hashes. You can crash your catalog if you modify the wrong thing. Referred to in your code as $Safe{config}, a reference to the hash containing the configuration structure. If you use this, it is recommended that you refer frequently to the MiniVend source code.

discount
Gives read-write access to session discounts, an anonymous hash. Referred to in your code as $Safe->{discounts}.

file
If specified, the anchor text is a file name to read the Perl code from. This allows code to be maintained in separate files, though you need to remember that any MiniVend tags contained will generally not be interpolated (depending on interpolation order and use of the [[any]] and [post] modifiers). The file name is relative to the MiniVend base directory unless specified as an absolute path.

frames
The true/false value determining whether frames processing is enabled. Read-only -- you can set the value with [frames-off] or [frames-on]. Referred to in your code as $Safe{frames}.

items
Gives read-only access to the items on order, for the current cart. This is an array of hashes, and includes the product code, quantity, and any modifiers you have specified. Referred to in your code as a reference to the array, $Safe{items} or @{$Safe{items}}.

# Product code of first item in cart $item_code = $Safe{items}->[0]->{code}; # Quantity for third item in cart $item_code = $Safe{items}->[2]->{quantity}; # Color of second item in cart $item_code = $Safe{items}->[2]->{color};

scratch
Gives read-write access to the scratch variables, a reference to an anonymous hash. Referred to in your code as $Safe{scratch}.

sub
If specified, the anchor text is a subroutine name and optional parameters to be passed. The subroutine can be defined in three ways; as a global subroutine (works for entire server); as a catalog-wide pre-defined subroutine; or in a scratchpad variable. All are called with the same syntax -- the arguments are passed in via the @_ argument array.

IMPORTANT NOTE: Global subroutines are not subject to the stringent security checking of the Safe module, so almost anything goes there. The subroutine will be able to modify any variable in MiniVend, and will be able to write to read and write any file that the MiniVend daemon has permission to write. Though this gives great power, it should be used with caution. Careful! They are defined in the main minivend.cfg file, so should be safe from individual users in a multi-catalog system.

Global subroutines are defined in minivend.cfg with the GlobalSub directive, or in user catalogs which have been enabled via AllowGlobal . Global subroutines are much faster than the others as they are precompiled. (Faster still are UserTag definitions.)

Catalog subroutines are defined in catalog.cfg , with the Sub directive. They are subject to the stringent Safe.pm security restrictions that are controlled by SafeUntrap . If you wish to have default arguments supplied to them, use the SubArgs directive.

Scratch subroutines are defined in the pages, and are also subject to Safe.pm checking. See the beginning of this section for an example of a subroutine definition. There is no ``sub name { }'' that surrounds it -- the subroutine is named from the name of the scratch variable.

values
Gives read-write access to the user variables, including the MiniVend special variables, an anonymous hash. Referred to in your code as %{Safe{'values'}} or $Safe{'values'}->{variable}.

# Read the user's selected shipping mode my $shipmode = $Safe{values}->{mv_shipmode};

The code can be as complex as desired, but cannot use any operators.that modify the file system or use ``unsafe'' operations like ``system'', ``exec'', or backticks. These constraints are enforced with the default permissions of the standard Perl module Safe -- operations may be untrapped on a system-wide basis with the SafeUntrap directive.

The result of the tag will be the result of the last expression evaluated, just as in a subroutine. If there is a syntax error or other problem with the code, there will be no output.

Here is a simple one which does the equivalent of the classic hello.pl program:

[perl] my $tmp = "Hello, world!"; $tmp; [/perl]

Of course you wouldn't need to set the variable -- it is just there to show the capability.

To echo the user's browser, but within some HTML tags:

[perl browser] my $html = '<H5>'; $html .= $Safe{'browser'}; $html .= '</H5>'; $html; [/perl]

To show the user their name, and the current time:

[perl values] my $string = "Hi, " . $Safe{values}->{'name'} ". The time is now "; $string .= localtime; $string; [/perl]

On-the-fly Catalog Pages

If an item is displayed on the search list (or order list) and there is a link to a special page keyed on the item, MiniVend will attempt to build the page ``on the fly''. It will look for the special page flypage.html , which is used as a template for building the page. If [item_field fieldname] , [item_price], (etc.) elements are used on the page, quite complex and information-packed pages can be built. The [if_field fieldname] HTML [/if_field] pair can be used to insert HTML only if there is a non-blank value in a particular field.

Because the tags are the same, an [item_list] cannot be used on an on-the-fly page. The [loop item, item] tag is still usable.

If the directive PageSelectField is set to a valid product database field which contains a valid MiniVend page name (relative to the catalog pages directory, without the .html suffix) it will be used to build the on-the-fly page.

Active tags in their order of interpolation:

[if-field field] Tests for a non-empty value in B<field> [if-data db field] Tests for a non-empty B<field> in B<db> [item-code] Product code of the displayed item [item-accessories args] Accessory information (see I<accessories>) [item-description] Description field information [item-price quantity*] Product price (at B<quantity>) [item-field field] Product database B<field> [item-data db field] Database B<db> entry for B<field>

Tags for controlling old syntax interpolation order

[[any]]
Forces early interpolation of any tag. Sometimes needed if the order of interpolation does not achieve the desired result (meaning you see MiniVend tags displayed on the page).

NOTE: This is ignored if using the new syntax.

[ n [any] HTML n ]
Where n is a single digit in the range 0-9. If present, it forces early interpolation of that region of MiniVend tags, and is differentiated from other early interpolation areas. The enclosed MiniVend tags will still be interpolated in the normal order, but it can usually be combined with the [post] [/post] pair to achieve the desired order.

NOTE: This is ignored if using the new syntax.

[post]
Selects an area that will not be interpolated until after the rest of the page is interpolated. If followed by a number, will match a terminating [/post] tag with the corresponding number.

NOTE: This is ignored if using the new syntax.

[/post]
Terminates a [post] region.

.

Required Pages

A number of HTML pages are required for MiniVend operation. Typically they are used to transmit error messages, status of search or order operations, and other out of boundary conditions.

NOTE: The distributed demo does not use these default values.

The names of these pages can be set with the SpecialPage directive. The standard pages and their default locations:

badsearch (pages/badsearch.html)
The error page displayed if there is a system or user error with the search engine. Overridden by mv_failpage if set on current form.

canceled (pages/canceled.html)
The page displayed by MiniVend when an order has been canceled by the user.

catalog (pages/catalog.html)
The main catalog page presented by MiniVend when another page is not specified.

checkout (pages/order.html)
The page the customer is sent to when checking out (the location pointed to by a [finish_order] tag.

confirmation (pages/confirmation.html)
After the order is completed, the confirmation page is displayed.

failed (pages/failed.html)
If the sendmail program could not be invoked to email the completed order, the failed.html page is displayed. (Sadly we don't know if the email was successfully delivered).

flypage (pages/flypage.html)
If the catalog page for an item was not found when its [item_link] is clicked, this page is used as a template to build an on-the-fly page. See On-the-fly Catalog Pages . If frames are in use, the special order page can be overridden with the one configured with the directive FrameFlyPage .

interact (pages/interact.html)
Displayed if an unexpected response was received from the browser, such as not getting expected fields from submitting a form. This would probably happen from typos in the html pages, but could be a browser bug.

missing (pages/missing.html)
This page is displayed if the URL from the browser specifies a page that does not have a matching .html file in the pages directory. This can happen if the customer saved a bookmark to a page that was later removed from the database.

needfield (pages/needfield.html)
Displayed if the user did not fill in a required field in the order form. See REQUIRED FIELDS.

nomatch (pages/nomatch.html)
This page is displayed if the search engine is used, but there is no match for the search specification and no [no_match] region found on the search page.

noproduct (pages/noproduct.html)
This page is displayed if the URL from the browser specifies the ordering of a product code which is not in the products file.

order (pages/order.html)
This page is displayed when the customer orders an item. It can contain any or all of the customer-entered values, but is commonly used as a status display (or ``shopping basket''). If frames are in use, the special order page can be overridden with the one configured with the directive FrameOrderPage .

search (pages/search.html)
Contains the default output page for the search engine results. Also required is an input page, which can be the same as search.html or an additional page.

violation (pages/violation.html)
Displayed if a security violation is noted, such as an attempt to submit a credit card number on a non-secured form when in ExtraSecure mode.

.

Checking Page HTML

MiniVend, as of release 3.02, allows you to debug your page HTML with an external page checking program. Because leaving this enabled on a production system is potentially a very bad performance degradation, the program is set in a the global configuration file with the CheckHTML directive.

To check a page for validity, set the global directive CheckHTML to the name of the program (don't do any output redirection). A good choice is the freely available program weblint -- it would be set in minivend.cfg with:

CheckHTML /usr/local/bin/weblint -s -

Of course you must restart the server for it to be recognized. The full path to the program should be used -- if you have trouble, check it from the command line (as you should with all external programs called by MiniVend).

Insert [tag flag checkhtml][/tag] at the top or bottom of pages you want to check, and the output of your checker should be appended to the browser output as a comment, visible if you view the page or frame source.

To do this only at times, use a Variable setting:

Variable CHECK_HTML [tag flag checkhtml][/tag]

and place __CHECK_HTML__ in your pages. You can then set the Variable to the empty string if you wish to disable it.


FORMS AND MINIVEND

MiniVend uses HTML forms for order, search, and control operations. Order operations possibly include ordering an item, selecting item size or other attributes, and reading user information for payment and shipment. Search operations may also be triggered by a form. In addition, the user can control certain aspects of the session, such as order security, frames presentation, and background display via a control form.

Special Form Fields

MiniVend treats some form fields specially, to link to the search engine and provide more control over user presentation. It has a number of predefined variables, most of whose names are prefixed with mv_ to prevent name clashes. It also uses a few variables which are postfixed with integer digits -- those are used to provide control in its iterating lists.

These special fields all begin with mv_, and include:

(O = order, S = search, C = control, A = all, X in scratch space)

Name Type Description mv_alinkcolor C Sets access link color mv_all_chars S Turns on punctuation matching mv_arg[0-9]+ A Parameters for mv_subroutine (mv_arg0,mv_arg1,...) mv_background C Explained in Controlling Page Appearance mv_base_directory S Sets base directory for search file names mv_bgcolor C Sets background color mv_case S Turns on case sensitivity mv_cartname O Sets the shopping cart name mv_cache_params S Determines caching of searches mv_change_frame A Any form, changes frame target of form output mv_check A Any form, sets multiple user variables after update mv_checkout O Sets the checkout page mv_click A Any form, sets multiple form variables before update mv_click XA Default mv_click routin, click is mv_click_arg mv_click <name> XA Routine for a click <name>, sends click as arg mv_click_arg XA Argument name in scratch space mv_coordinate S Enables field/spec matching coordination mv_credit_card* O Discussed in order security (some are read-only) mv_customcolors C Enables user-custom colors mv_dict_end S Upper bound for binary search mv_dict_fold S Non-case sensitive binary search mv_dict_limit S Sets upper bound based on character position mv_dict_look S Search specification for binary search mv_dict_order S Sets dictionary order mode mv_doit A Common to all forms, sets default action mv_email O Reply-to address for orders mv_errorpage O Sets error page if order check fails mv_exact_match S Sets word-matching mode mv_failpage O,S Sets page to display on failed order check/search mv_head_skip S Sets skipping of header line(s) in index mv_helpon C Turns on the help feature if defined mv_helpoff C Turns off the help feature if defined mv_linkcolor C Sets the link color mv_matchlimit S Sets match page size mv_max_matches S Sets maximum match return mv_min_string S Sets minimum search spec size mv_negate S Specifies that records NOT matching will be found mv_nextpage A Sets next page user will go to after submission mv_order_group O Allows grouping of master item/sub item mv_order_item O Causes the order of an item mv_order_number O Order number of the last order (read-only) mv_order_quantity O Sets the quantity of an ordered item mv_order_profile O Selects the order check profile mv_order_receipt O Sets the receipt displayed mv_order_report O Sets the order report sent mv_order_subject O Sets the subject line of order email mv_orderpage O Sets the page to display on refresh mv_orsearch S Selects AND/OR of search words mv_profile S Selects search profile mv_range_alpha S Sets alphanumeric range searching mv_range_look S Sets the field to do a range check on mv_range_max S Upper bound of range check mv_range_min S Lower bound of range check mv_resetcolors C Causes reset of user color maps mv_record_delim S Search index record delimiter mv_return_all S Return all lines found (subject to range search) mv_return_delim S Return record delimiter mv_return_fields S Fields to return on a search mv_return_file_name S Set return of file name for searches mv_return_spec S Return the MiniVend page specified in search string mv_save_session C Set to non-zero to prevent expiration of user session mv_search_field S Sets the fields to be searched mv_search_file S Sets the file(s) to be searched mv_search_match_count S Returns the number of matches found (read-only) mv_search_over_msg S Returns string indicating search overflow (read-only) mv_search_page S Sets the page for search display mv_searchspec S Search specification mv_searchtype S Sets search type (text or glimpse) mv_separate_items O Sets separate order lines (one per item ordered) mv_shipmode O Sets shipping mode for custom shipping mv_sort_command S Sets the command to use for sorting searches mv_sort_crippled S Sets crippled sort mode mv_sort_field S Field(s) to sort on mv_sort_option S Options for sort mv_spelling_errors S Number of spelling errors for Glimpse mv_substring_match S Turns off word-matching mode mv_subroutine A Subroutine to processing based on form mv_successpage O Page to display on successful order check mv_textcolor C Sets text color mv_todo A Common to all forms, sets form action mv_todo.map A Contains form imagemap mv_todo.checkout.x O Causes checkout action on click of image mv_todo.return.x O Causes return action on click of image mv_todo.submit.x O Causes submit action on click of image mv_todo.x A Set by form imagemap mv_todo.y A Set by form imagemap mv_vlinkcolor C Sets visited link color

Form Actions

Any MiniVend form can be used for any number of actions. The actions are mapped by the ActionMap directive in the catalog configuration file, and are selected on the form with either the mv_todo or mv_doit variables.

Mapping of actions in the ActionMap directive means that the value of the submit button is scanned to determine the action. To map the string ``Place Order'' to the action submit, you would put in the catalog.cfg file:

ActionMap submit place order

And on the form you would make a submit button:

<INPUT TYPE="submit" NAME="mv_todo" VALUE="Place Order">

When the button is clicked by the user, the submit action will be performed.

To set a default action for a form, set the variable mv_doit as a hidden variable:

<INPUT TYPE="hidden" NAME="mv_doit" VALUE="refresh">

When any other submit button (for a meaningless variable, the MiniVend demos use mv_submit) is pressed, the mv_todo value will not be found, so the refresh action defined in mv_doit will be used.

The defined actions are:

cancel
All user information (with the exception of the frames and secure variable settings) is erased, and the shopping cart is emptied. The user is then mv_nextpage or mv_orderpage.

checkout
The shopping cart and user variables are updated, and the user is sent to the page defined in the variable mv_checkout or the CheckoutPage directive.

control
The user help, frames, security, and color/background information is examined and settings changed if appropriate. The shopping cart and user variables are also updated.

refresh
Simply updates the user variables and returns to the page defined in mv_orderpage.

return
Updates the user variables and returns to the page defined in mv_nextpage, or the user's last non-order/non-search page. This is difficult to use, for it is hard to predict what that page will be. Setting mv_nextpage with the value of a scratch variable works well.

search
The shopping cart and user variables are updated, then the form variables are interpreted and the search specification contained therein is dispatched to the search engine -- results are returned on the defined search page (set by mv_search_page or the search page directives).

submit
Submit the form for order processing. If no order profile is defined with the mv_order_profile variable, the order will be checked to see if the current cart contains any items and be checked against the fields defined in the RequiredFields directive. Assuming those checks pass, the order will be submitted.

If there is an order profile defined, the form will be checked against the definition in the order profile and submitted if the pragma &final is set to yes. If &final is set to no (the default), and the check succeeds, the user will be routed to the MiniVend page defined in mv_successpage, mv_nextpage, or mv_orderpage. Finally, if the check fails, the user will be routed to mv_failpage, mv_nextpage, or mv_orderpage in that order.

.

One-click Multiple Variables

MiniVend can set multiple variables with a single button or form control. You first define the variable set (or profile, as in search and order profiles) inside a scratch variable:

[set Search by Category] mv_search_field=category mv_search_file=categories mv_todo=search [/set]

The special variable mv_click sets variables just as if they were put in on the form. It is controlled by a single button, as in:

<INPUT TYPE="submit" NAME="mv_click" VALUE="Search by Category">

When the user clicks the submit button, all three variables will take on the values defined in the ``Search by Category'' scratch variable. You can set the scratch variable on the same form as the button is on -- in fact that is recommended for clarity.

The variable will not be carried from form to form, it must be set on the form being submitted.

The special variable mv_check sets variables for the form actions checkout, control, refresh, return, search, and submit . This function operates after all of the values are set from the form, including the ones set by mv_click, and can be used to condition input to search routines or orders.

The variable sets can contain and be generated by most MiniVend tags -- the profile is interpolated for MiniVend tags before being used. Careful of interpolation order, and don't use the [post] tag -- it will not work. Embedded Perl will work, and is recommended for most conditional operations within the profile.

Any setting of variables already containing a value will overwrite the variable, so to build sets of fields (as in mv_search_field and mv_return_fields) you must use comma separation or place the null character with a &#0; literal.

Here is a small example which will set the value of mv_nextpage to route the user to a special page if their search inputs are invalid:

<FORM ... <INPUT TYPE=hidden NAME=mv_check VALUE="Invalid Input"> ... </FORM> [set Invalid Input] [perl cgi] my $type = $Safe->{cgi}->{mv_searchtype}; my $spell_check = $Safe->{cgi}->{mv_spelling_errors}; my $out = ''; if($spell_check and $type eq 'text') { $out .= "mv_todo=return\n"; $out .= "mv_nextpage=special/cannot_spell_check\n"; } return $out; [/perl] [/set]

mv_subroutine
The special variable mv_subroutine defines a named subroutine that will be called if defined on the current form. (This variable can have been set by mv_click.)

It takes arguments based on the special form variables mv_argN, where N is an integer that corresponds to the argument number (starting at zero). Arguments can be of four types:

identifier
Identifies a form variable (on the current form) the value of which will be supplied as that argument.

HASH(identifier)
Identifies a variable that will be parsed as a series of key-value pairs and supplied as a hash *reference*.

ARRAY(identifier)
Identifies a variable that will be parsed as a series of values and supplied as an array *reference*.

LITERAL(string)
A string that will be passed unchanged.

CODE(routine)
Identifies a named Perl subroutine that will be called to produce the argument. The arguments are a null-separated list placed in a variable of the same name, which will be parsed as above for HASH, ARRAY, LITERAL, identifier, and CODE references. The return value (hash reference, scalar, etc.) depends on the subroutine. This is recursive.

SAFE(list)
Identifies additional arguments passed to the subroutine parser, as in [perl sub values]. It will not be placed in the argument list, so you should use mv_arg9999 or some such to pass it from the original form. Never necessary or desirable when calling a GlobalSub.

The return value for the subroutine is available in the fixed .session variable return_value, accessible as [data session return_value].

An example would be a password-protected message. Here is a form:

<FORM METHOD=POST ACTION="[process-target]"> <INPUT TYPE=hidden NAME=mv_subroutine VALUE=disclose_secret> <INPUT TYPE=hidden NAME=mv_arg0 VALUE=message> <INPUT TYPE=hidden NAME=mv_arg1 VALUE=password> <INPUT TYPE=hidden NAME=mv_doit VALUE=return> <INPUT TYPE=hidden NAME=mv_nextpage VALUE=secret> Select <SELECT NAME=message> <OPTION VALUE="secret"> Secret <OPTION VALUE="top_secret"> Top Secret </SELECT> Password <INPUT TYPE=password NAME=password VALUE=""> <INPUT TYPE=submit VALUE="See a Secret"> </FORM>

And a subroutine:

[set disclose_secret] my($message, $password) = @_; my $out = ''; if($message =~ /^secret/) { return "Password is wrong." unless $password eq 'foo'; $out = "Software documentation might as well be a secret sometimes."; } elsif($message =~ /top_secret/) { return "Password is wrong." unless $password eq 'bar'; $out = "You can do a lot with software if you read the documentation!"; } return $out || 'No message like that'; [/set]

And a results page secret.html (remember, set the destination for the return action with mv_nextpage ):

<HTML> <HEAD> <TITLE>Secret?</TITLE> </HEAD> [body 1] Secret: [data session return_value] </BODY> </HTML>

Checks and Selections

You can provide a ``memory'' for drop-down menus, radio buttons, and checkboxes with the [checked] and [selected] tags.

[checked var_name value]
(new syntax [checked name=``var_name'' value=``value''])

This will output CHECKED if the variable var_name is equal to value . Not case sensitive.

[selected var_name value MULTIPLE*]
(new syntax [selected name=``var_name'' value=``value'' multiple=``yes''])

This will output SELECTED if the variable var_name is equal to value . If the optional MULTIPLE argument is present, it will look for any of a variety of values. Not case sensitive.

Here is a drop-down menu that remembers an item-modifier color selection:

<SELECT NAME="color"> <OPTION [selected color blue]> Blue <OPTION [selected color green]> Green <OPTION [selected color red]> Red </SELECT>

Here is the same thing, but for a shopping-basket color selection

<SELECT NAME="[modifier-name color]"> <OPTION [selected [modifier-name color] blue]> Blue <OPTION [selected [modifier-name color] green]> Green <OPTION [selected [modifier-name color] red]> Red </SELECT>

.

Setting Form Security

You can ensure that a form will be submitted securely (to the base URL in the SecureURL directive, that is) by specifying your form input to be ACTION=``[process-target frame secure]''. If you are not using frames, just specify the special frame ``_self'' or ``none''.

To submit a form to the regular non-secure server, just omit the secure modifier.

Stacking Variables on the Form

Many MiniVend variables can be ``stacked'', meaning they can have multiple values for the same variable name. As an example -- to allow the user to order multiple items with one click, you can set up a form like this:

<FORM METHOD=POST ACTION="[process-order]"> <input type=checkbox name="mv_order_item" value="M3243"> Item M3243 <input type=checkbox name="mv_order_item" value="M3244"> Item M3244 <input type=checkbox name="mv_order_item" value="M3245"> Item M3245 <input type=hidden name="mv_doit" value="refresh"> <input type=submit name="mv_junk" value="Order Checked Items"> </FORM>

The stackable mv_order_item variable with be decoded with multiple values, causing the order of any items that are checked.

To place a ``delete'' checkbox on your shopping basket display:

<FORM METHOD=POST ACTION="[process-order]"> [item-list] <input type=checkbox name="[quantity-name]" value="0"> Delete Part number: [item-code] Quantity: <input type=text name="[quantity-name]" value="[item-quantity]"> Description: [item-description] [/item-list] <input type=hidden name="mv_doit" value="refresh"> <input type=submit name="mv_junk" value="Order Checked Items"> </FORM>

In this case, first instance of the variable name set by [quantity-name] will be used as the order quantity, deleting the item from the form.

Of course, not all variables are stackable. Check the documentation for which ones can be stacked -- or experiment on your own.

Setting SQL tables with a form

Any MiniVend database can be updated with a form using the following method.

NOTE: If you are updating a non-SQL database, you will have to perform a [tag export database][/tag] operation if you wish to update the ASCII source file with the results of your update.

You of course may insert or update records in any SQL database with the [sql set] tag, but you may also do form-based updates or inserts.

In an update form, four special MiniVend variables are used to select the database parameters:

mv_data_table
The table to update.

mv_data_key
The field that is the primary key in the table. Must match the existing database definition.

mv_data_function
UPDATE or INSERT.

mv_data_fields
Fields from the form which should be inserted or updated. Must be existing columns in the table in question.

The MiniVend action set (see ActionMap ), causes the update. Here.is an pair of example forms. One is used to set the key to access the record (careful with the name, this one goes into the user session values). The second actually performs the update. It uses the [loop] tag with only one value to place default/existing values in the form based on the input from the first form:

<FORM METHOD=POST ACTION="[process-target]"> <INPUT TYPE=HIDDEN name="mv_doit" value="return"> <INPUT TYPE=HIDDEN name="mv_nextpage" value="update_proj"> Sales Order Number <INPUT TYPE=TEXT SIZE=8 NAME="update_code" VALUE="[value update_code]"> <INPUT TYPE=SUBMIT name="mv_submit" Value="Select"> </FORM> [new] <FORM METHOD=POST ACTION="[process-target]"> <INPUT TYPE=HIDDEN NAME="mv_data_table" VALUE="ship_status"> <INPUT TYPE=HIDDEN NAME="mv_data_key" VALUE="code"> <INPUT TYPE=HIDDEN NAME="mv_data_function" VALUE="update"> <INPUT TYPE=HIDDEN NAME="mv_nextpage" VALUE="updated"> <INPUT TYPE=HIDDEN NAME="mv_data_fields" VALUE="code,custid,comments,status"> <PRE> [loop arg="[value update_code]"] Sales Order <INPUT TYPE=TEXT NAME="code SIZE=10 VALUE="[loop-code]"> Customer No. <INPUT TYPE=TEXT NAME="custid" SIZE=30 VALUE="[loop-field custid]"> Comments <INPUT TYPE=TEXT NAME="comments" SIZE=30 VALUE="[loop-field comments]"> Status <INPUT TYPE=TEXT NAME="status" SIZE=10 VALUE="[loop-field status]"> [/loop] </PRE> <INPUT TYPE=SUBMIT name="mv_todo" Value="Set"> </FORM>

The variables in the form do not update the user's session values, so they can correspond to database field names without fear of corrupting the user session.


THE SEARCH ENGINE

MiniVend implements a search engine which will search the product database (or any other file) for items based on customer input. It uses either forms or URL-based searches (called with the special page name scan). The search engine uses many special MiniVend tags and variables.

Examples of search forms and result pages are included in the supplied demos.

Two search engine interfaces are provided, and five types of searching are available. The default is a text-based search of the products.asc file. A binary search of a dictionary-ordered file can be specified. An optional Glimpse search is enabled by placing the command specification for Glimpse in the directive Glimpse . There is a range-based search, used in combination with one of the above. And finally, there is an SQL search which translates the MiniVend search interface to SQL queries.

The default, a text based search, sequentially scans the lines in the target file. By default it returns the first field (delineated by the standard Delimiter ), for every line matching the search specification. This corresponds to the product code, which is then used to key specific accesses to the database.

The text-based search is capable of sophisticated field-specific searches with fully-independent case-sensitivity, substring, and negated matching. (There is not yet a full search language except for SQL queries, so AND/OR matching is not supported across multiple fields. Stay tuned for this in MiniVend 3.1 or later.)

The Search Form

A number of variables can be set on search forms to determine which search will be used, what fields in the database it will search, and what search behavior will be.

Here is a simple search form:

<FORM ACTION="[process-search]" METHOD=POST> <INPUT TYPE="text" SIZE="30" NAME="mv_searchspec"> <INPUT TYPE="submit" NAME="mv_todo" VALUE="Search"> </FORM>

When the ``Search'' submit button is pressed (or <ENTER> is pressed) MiniVend will search the products.asc file for the string entered into the text field mv_searchspec , and return the product code pertaining to that line.

The same search for a fixed string, say ``shirt'', could be performed with the use of a hot link, using the special scan URL:

[page scan/se=shirt]See our shirt collection![/page]

The default is to search every field on the line. If you only wished to match on the string shirt in the product database field ``description'', you could modify the search:

<INPUT TYPE="hidden" NAME="mv_search_field" VALUE="description">

In the hot-linked URL search:

[page scan/se=shirt/sf=description]See our shirt collection![/page]

If you want to let the user decide on the search parameters, you can use checkboxes or radiobox fields to set the fields:

Search by author <INPUT TYPE="checkbox" NAME="mv_search_field" VALUE="author"> Search by title <INPUT TYPE="checkbox" NAME="mv_search_field" VALUE="title">

Fields can be stacked -- if more than one is checked, all checked fields will be searched. (This doesn't work for Glimpse in the return_file_name mode, though).

Glimpse

To use the Glimpse search, you must build the Glimpse index based on files in your ProductDir , or wherever the files to be searched will be located. If you installed MiniVend in the default /usr/local/lib/minivend, the command line to build the index for the products file would be:

glimpseindex -b -H /usr/local/lib/minivend/products products.asc

There are several ways to improve search speed for large catalogs.

One method that works well for large products.asc files is to split the products.asc file into small index files (in the example, 100 lines) with the split(1) UNIX/POSIX command, then index it with glimpse:

split -100 products.asc index.asc. glimpseindex -H /usr/local/lib/minivend/products index.asc.*

This will dramatically increase search speeds for large catalogs, at least if the search term is relatively unique. If it is a common string, as you might have in a category search, you will be better off to use the text-based search.

If you are intending to search for numbers, add the -n option to the Glimpse command line.

(A large catalog is one of more than several thousand items -- smaller ones have acceptable speed in any of the search modes.)

If the Glimpse executable is not found at MiniVend startup, the Glimpse search will be disabled and the regular text-based search used instead.

There are several things you have to watch for while using glimpse, and a liberal dose of the Glimpse documentation is suggested. In particular, the spelling error capability will not work in combination with the field-specific search -- Glimpse selects the line, but MiniVend's text-based search routines disqualify it when checking to see if the search string is within one of the specified fields.

Fast Binary Search

Fast binary searching is useful for scanning large databases for strings that match the beginning of a line. They use the standard Perl module Search::Dict, and are enabled through use of the mv_dict_look , mv_dict_end , mv_dict_limit , mv_dict_fold , and mv_dict_order variables.

The search must be done on a dictionary-ordered pre-built index, production of which is left as an exercise for the user.

Hint: the field to search is the first field in the file, then the product code should be in the second field, delimited by Delimiter . You will also have to set mv_return_fields=1 to return the product code in the search.

Range Searching

Range searching allows you to qualify your search returns with a field that must be within a certain numeric or alphanumeric range. To use it, set the mv_range_look variable to the products database field, or a column/field number for another file. Then set the corresponding mv_range_min and mv_range_max variables with a selectable field.

<INPUT TYPE="hidden" NAME="mv_range_look" VALUE="price"> Search on Price Min <SELECT NAME="mv_range_min"> <OPTION value=0 SELECTED> Free <OPTION value=1000000> $1,000,000 <OPTION value=10000000> $10,000,000 <OPTION value=20000000> $20,000,000 <OPTION value=40000000> $40,000,000 </SELECT><BR> Max <SELECT NAME="mv_range_max"> <OPTION value=0 SELECTED> no object <OPTION value=1000000> $1,000,000 <OPTION value=10000000> $10,000,000 <OPTION value=20000000> $20,000,000 <OPTION value=40000000> $40,000,000 </SELECT>

The value of 0 for mv_range_max is equivalent to infinity if doing a numeric search. (This makes it impossible to search for a ceiling of 0 with a negative mv_range_min, just in case you were planning on trying that.)

The fields are stackable, so you can set more than one range to check. The order is significant, in the sense that the array of field names and minimum/maximum values must be kept in order to achieve correspondence.

The optional mv_range_alpha specification allows alphanumeric range matching for the corresponding field -- if it is set, and you have stacked the fields, they must all be set. The mv_case field does apply if it is set -- otherwise the comparison is without regard to case.

If you wish to do ONLY a range search, you must select all lines with mv_return_all=yes in order to make the search operate. Range-only searches will be quite slow for large databases, since every line must be scanned. It should be quite usable for catalogs of less than 10,000 items in size, given a fast machine. Using it in combination with another search technique (in the same query) will yield faster search returns.

SQL searches

MiniVend can formulate and execute SQL searches in much the same way as it does text or Glimpse searches. Because of the SQL language and the limitations a common subset places on the operation, not all parameters are supported.

The following variables are in effect for SQL searches:

mv_matchlimit S Sets match page size mv_numeric S Determines numeric status of column for ? bind mv_orsearch S Selects AND/OR of search terms mv_range_look S Sets the column to do a range check on mv_range_max S Upper bound of range check mv_range_min S Lower bound of range check mv_return_fields S Columns to return from query mv_search_field S Sets the column(s) to be searched mv_search_file S Sets the table to be searched mv_search_page S Sets the page for search display mv_searchspec S Search specification(s) mv_searchtype S Sets search type (text, glimpse, or sql) mv_sort_field S Column(s) to sort on mv_sort_option S Options for sort (only global reverse) mv_sql_query S SQL query text for simple query mv_substring_match S Turns off word-matching mode

Their two-letter abbreviations are in effect (as below), so you may easily do a one-click SQL search.

If you are using SQL for the products database, and the table you are searching is in the same SQL database, you don't need to specify the table other than in the query. If you are not using SQL for products, or it resides in a different database, then you must specify a MiniVend database identifier located in the same SQL database as the table you are querying. Use the mv_search_file variable:

<INPUT TYPE=hidden NAME=mv_search_file VALUE="inventory">

Once you have selected the database, you may query any table that is located within the same SQL data source.

There are two modes for SQL search:

Simple query substitution
To do a simple query, define the variable mv_sql_query to be a valid SQL query. In its simplest form:

<FORM METHOD=POST ACTION="[process-search]"> <INPUT TYPE=hidden NAME=mv_searchtype VALUE="sql"> <INPUT TYPE=hidden NAME=mv_sql_query VALUE="select code from products where category = 'Americana'"> <INPUT TYPE=SUBMIT VALUE="Americana"> </FORM>

When the user clicks the button, the query will be done and the results returned using the default search return page. You may set the return page with mv_search_page as in the other searches, but most other variables have no effect.

Another exception is the mv_searchspec variable, which when set with either user-entered text or by another method, will be inserted in place of a single question mark in the query:

<FORM METHOD=POST ACTION="[process-search]"> <INPUT TYPE=hidden NAME=mv_searchtype VALUE="sql"> <INPUT TYPE=hidden NAME=mv_sql_query VALUE="select code from products where category = ? "> <SELECT NAME=mv_searchspec> <OPTION> Americana <OPTION> Contemporary <OPTION> Impressionists <OPTION> Renaissance <OPTION> Surreallists </SELECT> <INPUT TYPE=SUBMIT VALUE="Go"> </FORM>

When the user selects one of the search categories, the value of mv_searchspec will be substituted for the question mark, and quoted if the field is not numeric in nature.

The spaces necessary in SQL queries make hand generation of one-click URLs pretty tedious. You may generate one-click searches easily using [tag sql] SQL [/tag]. For example, the query

<A HREF="[tag sql]SELECT code from products where category = 'Americana'[/tag]"> Americana </A>

generates HTML that starts out:

<A HREF="http://your.com/cgi-bin/simple/scan/sq=SELECT%20code%20from%20..."> Americana </A>

The actual URL is a bit too long to show. The same result would be generated by:

[page scan/sf=category/se=Americana/st=sql] Americana [/page]

The first example may be more intuitive for some; it is marginally faster.

Complex form-based query
Within the confines of the variables in use for SQL searches, you may generate some pretty complex queries. The principles are much the same as for the other searches, but the implementation differs a bit.

For example, if you don't specify a field or fields in the table to search, MiniVend will search all fields as is the default for the text and Glimpse searches. This can be quite inefficient, as the resulting query looks something like:

select code from products WHERE title = 'Van Gogh' OR artist = 'Van Gogh' OR description = 'Van Gogh' OR price = 'Van Gogh' etc.

You get the picture. Each field is checked in turn. Much better is to set the mv_search_field variable to the field(s) you wish searched, skipping the ones that make no sense:

<INPUT TYPE=hidden NAME=mv_search_field VALUE=artist> <INPUT TYPE=hidden NAME=mv_search_field VALUE=title>

This generates a much more limited query.

If there are more mv_searchspec values than fields, then only the first search field is used. The below query will fail, as the second and subsequent search fields are ignored.

<INPUT NAME=mv_searchspec VALUE="Van Gogh"> <INPUT NAME=mv_searchspec VALUE="Dali"> <INPUT TYPE=hidden NAME=mv_search_field VALUE="title"> <INPUT TYPE=hidden NAME=mv_search_field VALUE="artist">

If there are more mv_search_field values than mv_searchspec values, then only the first search specification will be used:

<INPUT NAME=mv_searchspec VALUE="Van Gogh"> <INPUT NAME=mv_searchspec VALUE="Dali"> <INPUT TYPE=hidden NAME=mv_search_field VALUE="title"> <INPUT TYPE=hidden NAME=mv_search_field VALUE="artist"> <INPUT TYPE=hidden NAME=mv_search_field VALUE="museum">

The string 'Dali' will never be looked for.

If the number of search fields and search specs are the same, a coordinated AND search is done, and only rows matching all searchspecs will be found.

The mv_range_look facility is in use for the complex form query as well, and operates in exactly the same way.

The following search will find all Van Gogh paintings that are between $1,000,000 and $20,000,000, providing the price field is a numeric data type. It also illustrates the use of some other MiniVend variables that are usable for SQL searches.

<FORM METHOD=POST ACTION="[process-search]"> <INPUT TYPE=hidden NAME=mv_searchtype VALUE="sql"> <INPUT NAME=mv_searchspec VALUE="Van Gogh"> <INPUT TYPE=hidden NAME=mv_search_field VALUE="artist"> <INPUT TYPE=hidden NAME=mv_range_look VALUE="price"> <INPUT TYPE=hidden NAME=mv_range_min VALUE="1000000"> <INPUT TYPE=hidden NAME=mv_range_max VALUE="20000000"> <INPUT TYPE=hidden NAME=mv_return_fields VALUE="code,description"> <INPUT TYPE=hidden NAME=mv_sort_field VALUE="price"> <INPUT TYPE=hidden NAME=mv_sort_option VALUE="r"> </FORM>

It will generate the query:

SELECT code, description FROM products WHERE artist = 'Van Gogh' AND price >= 1000000 AND price <= 20000000 ORDER BY price DESC

.

One-click searches

MiniVend allows you to pass a search in a URL. Just specify the search with the special page reference scan. Here is an example:

[page scan/se=Impressionists/sf=category] Impressionist Paintings [/page]

Here is the same thing from a home page (assuming /cgi-bin/vlink is the CGI path for MiniVend's vlink):

<A HREF="/cgi-bin/vlink/scan/se=Impressionists/sf=category"> Impressionist Paintings </A>

The two-letter abbreviations are mapped with these letters:

DL mv_raw_dict_look ms mv_min_string SE mv_raw_searchspec ne mv_negate ac mv_all_chars nu mv_numeric bd mv_base_directory os mv_orsearch co mv_coordinate ra mv_return_all cs mv_case rd mv_return_delim de mv_dict_end rf mv_return_fields df mv_dict_fold rg mv_range_alpha di mv_dict_limit rl mv_range_look dl mv_dict_look rm mv_range_min do mv_dict_order rn mv_return_file_name dr mv_record_delim rs mv_return_spec em mv_exact_match rx mv_range_max er mv_spelling_errors se mv_searchspec fi mv_search_file sf mv_search_field fn mv_field_names sp mv_search_page hs mv_head_skip st mv_searchtype id mv_index_delim su mv_substring_match ml mv_matchlimit tc mv_sort_command mm mv_max_matches tf mv_sort_field mp mv_profile to mv_sort_option ms mv_min_string ty mv_sort_crippled

They can be treated just the same as form variables on the page, except that they can't contain spaces, '/' in a file name, or quote marks. These characters can be used in URL hex encoding, i.e. %20 is a space, %2F is a /, etc. -- &sp; or &#32; will not be recognized.

To replace a / (slash) in a file name (for the sp, bd, or fi parameter) you must use the shorthand of ::, i.e. sp=results::standard. (This may not work for some browsers, so you should probably either put the page in the main pages directory or define the page in a search profile.)

So if you wish to do an OR search on the fields category and artist for the strings ``Surreal'' and ``Gogh'', while matching substrings, you would do:

[page scan/se=Surreal/se=Gogh/os=yes/su=yes/sf=artist/sf=category] Van Gogh -- compare to surrealists [/page]

In-page searches

NOTE: New to MiniVend 3.03.

You may specify a search inside a page with the [search se=searchstring] tag. The parameters are the same as the the one-click search, and the output is always a newline-separated list of the return objects -- by default a series of item codes. The output of a [search ...] tag should almost always be passed to a [loop LIST] [/loop] tag pair for iteration.

Here is an example which will search for and show a series of products that match the categories Americana and Contemporary within the products database field category .

[loop [search se=Americana/se=Contemporary/os=yes/sf=category]] Artist: [loop-field artist]<BR> Title: [loop-field title]<P> [/loop]

The advantage of the in-page search is that you can embed searches within searches, and you can have straight unchanging links from static HTML pages.

Search Profiles

You can predefine an unlimited number of search profiles that reside in a file or files. To use this, make up a series of lines like:

mv_searchfield=artist mv_searchfield=category mv_orsearch=yes

These correspond to the MiniVend search variables that can be set on a form. You can set it right on the page that contains the search.

[set artist_profile] mv_searchfield=artist mv_searchfield=category mv_orsearch=yes [/set]

Then in the search form, set a variable with the name of the profile:

<INPUT TYPE=hidden NAME=mv_profile VALUE=artist_profile>

In a one-click search, you use the mp modifier:

[page scan/se=Leonardo/mp=artist_profile]A left-handed artist[/page]

You can also place them in a file. Define the file name in the SearchProfile directive. (You must reconfig the catalog for MiniVend to read it.) The profile is named by placing a name following a __NAME__ pragma:

__NAME__ title_search

The __NAME__ must begin the line, and be followed by whitespace and then the name.

The special variable mv_last stops interpretation of search variables. The following variables are always interpreted:

mv_dict_look mv_searchspec mv_range_look mv_range_min mv_range_max

Other than that, if you set mv_last in a search profile, and there are other variables on the search form, they will not be interpreted.

If you want to place multiple search profiles in the same file, separate them with __END__, which must be on a line by itself.

Search Reference

The supplied simple/srchform.html and simple/results.html pages show example search forms. You can modify them to present the search in any way you like -- just be careful to use the proper variable names for passing to MiniVend. It is also necessary that you copy the hidden variables as-is -- they are required to interpret the request as a search.

NOTE: The following definitions frequently refer to field name and column and column number -- all are the references to the columns of a searched text file as separated by delimiter characters.

The field names can be specified in several ways.

products.asc
If the file to be searched is left empty in the search form or definition (set with mv_search_file ), then the products.asc file will be searched, and field names are already available as named in the first line of products.asc .

other database files
If the file or files to be searched are ASCII delimited files, and have field names specified on the first line of the file, MiniVend will read the first line (of the first file) and determine the field names.

other files
If the file or files to be searched are ASCII delimited files, but don't have field names specified on the first line of the file, you can set the variable mv_field_names to a comma-separated list of field names as they will be referenced.

Fields can also always be specified by an integer column number, with 0.as the first column. This may reduce system processing somewhat, since the field names don't have to be indexed every time they are referenced, and won't have to be read from disk.

mv_all_chars
Set this if you anticipate searching for lots of punctuation characters that might be special characters for Perl -- the characters ()[]\$^ are included.

mv_base_directory
In the text search, set to the directory from which to base file searches. File names without leading / characters will be based from there. In the Glimpse search, passed to Glimpse with the -H option, and Glimpse will look for its indices there. Default is ProductDir.

mv_case
If this item is set to yes, the search will return items without regard to upper or lower case. This is the default -- set to yes if case should be matched. Implement with a checkbox <INPUT TYPE=CHECKBOX> field.

If stacked to match the mv_search_field and mv_searchspec variables, and mv_coordinate is set, it will operate only for the corresponding field.

mv_coordinate
If this item is set to yes, and the number of search fields equals the number of search specs, the search will return only items that match field to spec. (The search specifications are set by stacked mv_searchspec and mv_search_field variables.)

Case sensitivity, substring matching, and negation all work on a field-by field basis according to the following:

.

  • mv_dict_end If the string at the beginning of a line lexically exceeds this value, matching will stop. Ignored without mv_dict_look.

  • mv_dict_fold Make dictionary matching case-insensitive. Ignored without mv_dict_look. NOTE: This is the reverse sense from mv_case.

  • mv_dict_limit Automatically set the limiting string (mv_dict_end) to be one character greater than the mv_dict_look variable, at the character position specified. A value of 1, for instance, will set the limiting string to ``fprsythe'' if the value of mv_dict_look is ``forsythe''. A useful value is -1, which will increment the last character (setting the mv_dict_end to ``forsythf'' in our example). This prevents having to scan the whole file once a unique match is found.

    The order of this and the mv_dict_end variable is significant -- each will overwrite the other.

  • mv_dict_look The string at which to begin matching at in a dictionary-based search. If not set, the mv_dict_end, mv_dict_fold, and mv_dict_case variables will be ignored. May be set in a search profile based on other form variables.

  • mv_dict_order Make dictionary matching follow dictionary order, where only word characters and whitespace matter. Ignored without mv_dict_look.

  • mv_doit This must be set to search to make this a search page.

  • mv_exact_match Normally MiniVend searches match words, as opposed to sentences. This behavior can be overridden with mv_exact_match, which when set will place quotes around any value in mv_searchspec or mv_dict_look.

  • mv_field_names Deprecated in favor of in-list sorting.

    Defines the field names for the file being searched. This guarantees that they will be available, and prevents a disk access if using named fields on a search file (that is not the product database ASCII source, where field names are already known). This must be exactly correct, or it will result in anomalous search operation. Usually passed in a hidden field or search profile as a comma-separated list.

    NOTE: You should use this on the product database only if you plan on both pre-sorting with mv_sort_field and then post-sorting with [sort]field:opt[/sort].

  • mv_head_skip Normally MiniVend searches all lines of an index/product file but the first. Set this to the number of lines to skip at the beginning of the index. Default is 1 for the text search, which skips the header line in the product file. Default is 0 for a Glimpse search.

  • mv_index_delim Sets the delimiter for counting fields in a search index. The default is the same as the Delimiter directive.

  • mv_matchlimit The page size for matches that are returned. If more matches than mv_matchlimit are found, the search paging mechanism will be employed if the proper [more_list] is present. Can be implemented as a scrolling list (INPUT TYPE=SELECT) or radiobox (INPUT TYPE=RADIO) field.

  • mv_max_matches The maximum number of records that will be returned in a search. Default is 2000.

  • mv_min_string Sets the minimum size of a search string for a search operation. Default is 4 for the Glimpse search, and 1 for the text search.

  • mv_negate Specifies that records NOT matching the search criteria will be returned. Default is no. It is not operative for the Glimpse search.

    If stacked to match the mv_search_field and mv_searchspec variables, and mv_coordinate is set, it will operate only for the corresponding field.

  • mv_orsearch If this item is set to yes, the search will return items matching any of the words in searchspec. The default is no.

  • mv_profile Selects one of the pre-defined search specifications set by the SearchProfile directive. If the special variable within that file, mv_last, is defined, it will prevent the scanning of the form input for further search modifications. The values of mv_searchspec and mv_dict_look are always scanned, so you can specify this to do the equivalent of setting multiple checkboxes or radioboxes with one click, while still reading the search input text.

  • mv_range_alpha Sets the type of match, numeric or alphanumeric, for the range search in its corresponding range field. The search will return true (assuming it is greater than the mv_range_min specification) if the field searched is less than or equal to mv_range_max, in an alphanumeric sense.

  • mv_range_look This sets a field to scan for a range of numbers. It must be accompanied with corresponding mv_range_min and mv_range_max variables. It can be specified with either a field name or a column number.

  • mv_range_max Sets the high bound for the range search in its corresponding range field. The search will return true (assuming it is greater than the mv_range_min specification) if the field searched is less than or equal to mv_range_max. To set the bound at infinity, or whatever your integer limit is, set mv_range_min to 0.

  • mv_range_min Sets the low bound for the range search in its corresponding range field. The search will return true (assuming it is less than the mv_range_max specification) if the field searched is less than or equal to mv_range_min.

  • mv_record_delim Sets the delimiter for counting records in a search index. The default is newline, which works for the products and most line-based index files.

  • mv_return_fields The fields that should be returned by the match, specified either by field name or by column number. You should almost always specify 0 as the first field to be returned if searching the products database, since that is the key for accessing database fields.

  • mv_search_field The field(s) to be searched, specified either by column name or by column number.

    If the number of instances matches the number of fields specified in the mv_searchspec variable, and mv_coordinate is set to true, each search field (in order specified on the form) will be matched with each search spec (again in that order).

  • mv_search_file In the text search, set this variable to the file(s) to be scanned for a match. The default, if not set, is to scan the products.asc file. If set multiple times in a form (for a text search), will cause a search all the files. One file name per instance.

    In the Glimpse search, follows the Glimpse wildcard-based file name matching scheme. Use with caution and a liberal dose of the Glimpse man page.

  • mv_search_match_count Set by the search to indicate the total number of matches found.

  • mv_search_over_msg The message that should be displayed if there is an overflow condition (max_matches is exceeded). Overrides the SearchOverMsg directive -- it is cleared by MiniVend if there is no overflow. Somewhat deprecated by match paging.

  • mv_search_page The MiniVend-style name of the page that should display the search results. Overrides the FrameSearchPage directive, and the default value of search .

  • mv_searchspec The actual search string that is typed in by the customer. It is a text INPUT TYPE=TEXT field, or can be put in a select (drop-down) list to enable category searches. If multiple instances are found, they will be concatenated just as if multiple words had been placed in a text field.

    The user can place quotes around words to specify that they match as a string. To enable this by default, use the mv_exact_match variable.

    If mv_dict_look has a value, and mv_searchspec does not, then mv_searchspec will be set to the value of mv_dict_look.

    If the number of instances matches the number of fields specified in the mv_search_field variable, and mv_coordinate is set to true, each search field (in order specified on the form) will be matched with each search spec (again in that order).

  • mv_searchtype If set to glimpse, selects the Glimpse search (if Glimpse is defined).

    If set to sql, formulates an SQL select statement to return the search list.

    If set to text, selects the text-based search.

    Defaults to text if Glimpse is not defined, to Glimpse if it is. This can allow use of both search types if that is desirable -- for instance, searching for very common strings is better done by the text-based search. An example might be searching for categories of items instead of individual items.

  • mv_sort_command Set to a path name that will access the standard UNIX sort command -- the default is of course sort. If the sort command does not accept field-specific options, as more recent sorts like the GNU sort command do, set mv_sort_crippled to yes.

  • mv_sort_field (Most new users should ignore and use in-list sorting.)

    The file field(s) the search is to be sorted on, specified in one of two ways. If the file(s) to be searched have a header line (the first line) that contains Delimiter -separated field names, it can be specified by field name. If can also be specified by column number (the code or key is specified with a value of 0, for both types). These can be stacked, if coming from a form, or placed in a single specification separated by commas.

    NOTE FOR ADVANCED USERS: If specifying a sort for the product database, mv_field_names must be specified if you will be doing a fieldname-addressed post-sort.

  • mv_sort_option (Most new users should ignore and use in-list sorting.)

    The way that each field should be sorted. The flags are r, n, and f -- for reverse, numeric, and case-insensitive respectively. These can be stacked, if coming from a form, or placed in a single specification separated by commas. The stacked options will be applied to the sort fields as they are defined, presuming those are stacked.

  • mv_spelling_errors The number of spelling errors that will be tolerated. Ignored unless using Glimpse. If you have a large catalog, you might wish to limit this to two.

  • mv_substring_match If mv_substring_match is set to yes, matches on substrings as well as whole words. You would typically want to set this for dictionary-based searches.

    If stacked to match the mv_search_field and mv_searchspec variables, and mv_coordinate is set, it will operate only for the corresponding field.

    .

    The Results Page

    Once a search has been done, there needs to be a way of presenting the output. By default, the special page search.html is used -- but any number of search pages can be specified by passing the value in the search form, specified in the variable mv_search_page .

    On the search page, some special MiniVend tags are used to format the otherwise standard HTML. Each of the iterative tags is applied to every code returned from the search -- this is normally the product code, but could be a key to any of the arbitrary databases. The value placed by the [item-code] tag is set to whatever the first field (separated by whitespace) is, at least when the default of yes is in the UseCode directive.

    [search_list]
    Starts the representation of a search list. MiniVend tags can be embedded in the search list, yielding a table or formatted list of items with part number, description, price, and hyperlinks to order or go to its catalog page.

    In particular, all of the item tags described under order page are active. The most useful one might be [item_link], which if properly used, can allow the user to search the catalog for an item, then click a link to go to detailed catalog page for the item.

    In fact, any of the MiniVend database access tags can be used, allowing you to pull data from any of the fields in any of your predefined databases. Along with the MiniVend conditional tags, very complex pages can be built for each individual item returned in the search.

    [/search_list]
    Ends the search list.

    [no_match]
    Starts the region of the search results page that should be returned if there is no match (and no error) for the search. If this is not on the page, the special page nomatch will be displayed instead.

    [/no_match]
    Ends the no match region.

    [sort database:field:option* database:field:option*]
    Sorts the search list return based on database fields. If no options are supplied, sorts according to the return code. See SORTING .

    [sort]<options>[/sort]
    (This form of sort is deprecated, as it is difficult to use. Use the above method.)

    Placed inside the search list. Causes sorting of the search return based on the passed options. The fields that are there to sort are set by mv_return_fields .

    The field options passed in either numeric or field name form. If they are field numbers, they are numbered as sent to the search list in the order specified by mv_return_fields , starting from 0 and proceeding upwards. If column names, they are as found in the first record of the searched file (by default the ASCII source for the product database), except for the key or first field. followed by a required colon (:) and the options, if any.

    Accepts none, any, or combinations of the flags:

    f case-insensitive sort (folded) (mutually exclusive of n) n numeric order (mutually exclusive of f) r reverse sort

    The <options> are a field number and an optional flag or flags, in a similar fashion to the Unix sort command, and are interpolated for form values before being used. As an example, if you set up the following fields on your search form:

    <INPUT TYPE="hidden" NAME="mv_return_fields" VALUE="0,title,artist,price"> <INPUT TYPE="radio" NAME="the_sort_field" VALUE="title"> Sort by Title <INPUT TYPE="radio" NAME="the_sort_field" VALUE="artist"> Sort by Artist <INPUT TYPE="radio" NAME="the_sort_option" VALUE=""> Forward sort <INPUT TYPE="radio" NAME="the_sort_option" VALUE="r"> Reverse sort NOTE: The 0 refers to the database code/key used for [item-code]

    This would combine with the following search result page fragment to sort by either title or artist.

    [search-list] [sort] [value the_sort_field]:[value the_sort_option] [/sort] The [value...] lines will end up looking like artist:r or title:. This could also be specified with 2r or 1 .

    PERFORMANCE TIP: on heavily trafficked systems, it will pay to use only column numbers rather than named fields, as it reduces processing and may obviate an access to the searched file to find the field names.

    [uniq]
    Placed immediately after the [sort] tag (after [search-list] if doing sorts via mv_sort_field). If specified on a sorted return list, causes only the first line containing an [item-code] to be returned -- all subsequent lines will not be interpreted on the list. Note that [matches] and [more-list] may not operate as you wish in this case. Note that [on-change] is more likely useful.

    [on_change marker]
    Active only within [search-list][/search-list].

    Along with the companion [/on_change marker] , surrounds a region which should only be output when a field (or other repeating value) changes its value. This allows indented lists similar to database reports to be easily formatted. The repeating value must be a tag interpolated in the search process, such as [item-field field] or [item-data database field].

    Of course, this will only work as you expect when the search results are properly sorted.

    The marker field is mandatory, and is also arbitrary, meaning that you can select any marker you wish as long as it matches the marker associated with [/on_change marker] . The value to be tested is contained within a [condition]value[/condition] tag pair. The [on_change marker] tag also processes an [else] [/else] pair for output when the value does not change. The tags may be nested as long as the markers are different.

    Here is a simple example for a search list that has a field category and subcategory associated with each item:

    <TABLE> <TR><TH>Category</TH><TH>Subcategory</TH><TH>Product</TH></TR> [search-list] <TR> <TD> [on-change cat] [condition][item-field category][/condition] [item-field category] [else] &nbsp; [/else] [/on-change cat] </TD> <TD> [on-change subcat] [condition][item-field subcategory][/condition] [item-field subcategory] [else] &nbsp; [/else] [/on-change subcat] </TD> <TD> [item-field name] </TD> [/search-list] </TABLE>

    The above should put out a table that only shows the category and subcategory once, while showing the name for every product. (The &nbsp; will prevent blanked table cells if you use a border.)

    [/on_change marker]
    Companion to [on_change marker] .

    [matches]
    Replaced with the range of match numbers displayed by the search page. Looks something like ``1-50''. Make sure you insert this item between a [more_list] and [/more_list] element pair.

    [more_list next_img* prev_img* page_img* border* border_current*]
    Starts the section of the search page which is only displayed if there are more matches than specified in mv_matchlimit . If there are less matches than the number in mv_matchlimit, all text/html between the [more_list] and [/more_list] elements is stripped.

    Use in conjunction with the [more] element to place pointers to additional pages of matches.

    If the optional arguments next_img, prev_img, and/or page_img are present, they represent image files that will be inserted instead of the standard 'Next', 'Previous', and page number. If prev_img is none, then no previous link will be output. If page_img is none, then no links to pages of matches will be output. These are URLs, are substituted for with ImageDir , and will be encased in IMG tags. Lastly, border is the border number to put.

    In addition, if page_img is used, it will be passed an argument of the digit that is to be represented. This would allow an image generator program to be used, generating page numbers on the fly. The border and border_selected values are integers indicating the border that should be put around images in the page_img selection. The <border_selected> is used for the current page if set.

    As an example, if you use [more-list next.gif prev.gif page_num.cgi], the following will be the anchors:

    Previous <IMG SRC="prev.gif"> Page 1 <IMG SRC="/cgi-bin/page_num.cgi?1"> Page 2 <IMG SRC="/cgi-bin/page_num.cgi?2"> Next <IMG SRC="next.gif">

    [/more_list]
    Companion to [more_list].

    [more]
    Inserts a series of hyperlinks that will call up the next matches in a series. They look like this:

    Previous 1 2 3 4 5 6 Next

    The current page will not be a hyperlink. Every time the new link is pressed, the list is re-built to correspond to the current page. If there is no Next or Previous page, that link will not be shown.

    See the fr_resul.html or search.html files for examples. Make sure you insert this item between a [more_list] and [/more_list] element pair.

    [item_link code]
    Expands into a hyperlink which will jump the user to a page under the ItemLinkDir (default is the pages directory), with anchor text as set in ItemLinkValue (default is ``More Details''). If the page is not present, then flypage.html will be used to build a page from the entry in the database. If that doesn't work (perhaps due to a missing flypage.html) then the error page notfound.html will be displayed. Only active in the search list.

    [process_search]
    Calls the search with the proper URL, including MiniVend session tags. Used as the ACTION value for the search form.

    [process_target frame]
    Calls the search with the proper URL, including MiniVend session tags. Used as the ACTION value for the search form if the results are to be targeted to a different window than the one set by SearchFrame (which is ``_self'' by default).

    .

    Updating session variables after a search

    You may notice that if you set a scratch variable or reference a variable set in a search routine on the results page, the change does not stay in the user session.

    To change this, set the scratch variable mv_put_session on the page in question:

    [set mv_put_session]Yes[/set]

    This setting is persistent, so it is recommended that you do it once at the beginning of the user session if you wish it to be the default. If you don't want it to be the default, reset it to the empty value (or zero) on another page:

    [set mv_put_session][/set]

    Using a Search Cache

    Each catalog may maintain a search cache, which is enabled by specifying a file name (the name of the search cache DBM) in the SearchCache directive in catalog.cfg . It operates by developing a 32-bit checksum of the combined parameters of a one-click scan search, or by combining the variable names/values specified in mv_cache_params on a form-based search.

    If your catalog frequently specifies category searches in a large catalog, speed of search return can be increased by a large factor.

    You needn't do more than just enable the cache for one-click searches. To make them operate on a form-based search, specify the form variable names, separated by a spaces and/or a comma, that will generate a unique cache key. Example:

    <INPUT TYPE=hidden NAME="mv_cache_params" VALUE="mv_searchspec,mv_substring_match,mv_search_field">

    If you have the MD5 module installed on Perl, it will be used to generate the cache keys. This will guarantee a unique cache ID.

    If you don't have MD5 installed, a 32-bit checksum will be used to create the cache key. It is conceivable, but unlikely, that two separate searches could generate the same 32-bit checksum and return the same cached search.

    IMPORTANT NOTE: The search cache is only invalidated by a catalog reconfiguration. If you change your product database or any other files you search, you should reconfigure or the search returns may be wrong.

    Search caching is disabled on a client-by-client basis if the client browser does not have cookie capability, for the generated session numbers would be incorrect otherwise.


    THE ORDER PROCESS

    MiniVend has a completely flexible order basket and checkout scheme. The simple demo presents a common use of this process, in the directory pages/ord -- the files are:

    basket.html The order basket displayed by default checkout.html The form where the customer enters their billing and shipping info receipt.html The receipt displayed to the customer report.html The order report mailed to you

    It is not strictly necessary to display an order basket when an item is ordered. If you specify a different page to be displayed that is fine, but most customers will be confused if you don't give them an indication that the order operation has succeeded.

    Any order basket is an HTML FORM. It will have a number of variables on it. At the minimum it must have an [item-list] to loop through the items, and the quantity of each item must be set in some place on that form. Any valid MiniVend tags may be used on the page, and you may use multiple item lists if necessary.

    How to set up an order link

    On a product display page, use:

    [order 00-0011]Order the Mona Lisa[/order]

    If coming from a search results or on-the-fly page, you may use the generated [item-code] thusly:

    [order [item-code]]Order [item-field name][/order]

    Bear in mind that if you have not reached the page via a search or on-the-fly operation, [item-code] means nothing and will cause an error.

    How to set up an order button

    MiniVend can order via form submission as well. This allows you to order a product (or group of products) via a form button. In its simplest form, it is:

    <FORM ACTION="[process-target]" METHOD=POST> <INPUT TYPE=hidden NAME=mv_todo ACTION=refresh> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011"> <INPUT TYPE=submit VALUE="Order the Mona Lisa"> </FORM>

    The default quantity is one. An initial quantity may be set by the user by adding an mv_order_quantity variable:

    Number to order:<INPUT TYPE=text NAME=mv_order_quantity VALUE="1">

    You can order multiple items by stacking the variables:

    <FORM ACTION="[process-target]" METHOD=POST> <INPUT TYPE=hidden NAME=mv_todo ACTION=refresh> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011"> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a"> <INPUT TYPE=submit VALUE="Order the Mona Lisa with frame"> </FORM>

    Initial size or color may be set as well, provided UseModifier is set up properly:

    <INPUT TYPE=hidden NAME=mv_order_size VALUE="L">

    If the order is coming from a generated flypage, loop list, or search results page, you can get a canned select box from the [item-accessories size] or [item-accessories size] tag. See Item Attributes .

    Order Groups

    MiniVend 3.06 allows you to group items together, making a master item and sub-items. This can be used to delete accessories or options when the master item is deleted. In its simplest form, you order just one master item and all subsequent items are sub-items.

    <FORM ACTION="[process-target]" METHOD=POST> <INPUT TYPE=hidden NAME=mv_todo ACTION=refresh> <INPUT TYPE=hidden NAME=mv_order_group VALUE="1"> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011"> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a"> <INPUT TYPE=submit VALUE="Order the Mona Lisa with frame"> </FORM>

    If you wish to stack more than one master item, then you must define mv_order_group for all items, with either a 1 value (master) or 0 value (sub-item). A master owns all subsequent sub-items until the next master is defined.

    <FORM ACTION="[process-target]" METHOD=POST> <INPUT TYPE=hidden NAME=mv_todo ACTION=refresh> <INPUT TYPE=hidden NAME=mv_order_group VALUE="1"> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011"> <INPUT TYPE=hidden NAME=mv_order_group VALUE="0"> <INPUT TYPE=hidden NAME=mv_order_item VALUE="00-0011a"> <INPUT TYPE=hidden NAME=mv_order_group VALUE="1"> <INPUT TYPE=hidden NAME=mv_order_item VALUE="19-202"> <INPUT TYPE=hidden NAME=mv_order_group VALUE="0"> <INPUT TYPE=hidden NAME=mv_order_item VALUE="99-102"> <INPUT TYPE=submit VALUE="Order items"> </FORM>

    When the master item 00-0011 is deleted from the basket, 00-0011a will be deleted as well. And when 19-202 is deleted, then 99-102 will be deleted from the basket.

    NOTE: You cannot use checkboxes for this type of thing, for they do not pass a value when unchecked. Use radio groups or select/drop-down buttons.

    The attributes mv_mi and mv_si are set to the group and subitem status of each item. The group, contained in the attribute mv_mi, is a meaningless yet unique integer. All items in a group will have the same value of mv_mi. The attribute mv_si is set to 0 if the item is a master item, and 1 if it is a sub-item. if the item is a master item, and

    Basket display

    The basket page(s) are where the items are tracked and adjusted by the customer. It is possible to have an unlimited number of basket pages. It is also possible to have multiple shopping carts, as in buy or sell. This allows a basket/checkout type of ordering scheme, with custom order pages for items which have many accessories.

    The name of the page to display can be configured in several ways:

    1. Set the SpecialPage order to the page to display when an item is ordered.

    2. Set the FrameOrderPage directive to the page to use when frames are enabled. This overrides option 1.

    3. Use the [order item cart/page] Order it! [/order] form of order tag to specify an arbitrary order page for an item.

    4. If already on an order page, set the mv_checkout, mv_orderpage, mv_nextpage, mv_successpage, or mv_failpage variables.

    The variables mentioned above modify the page display in the.following ways:

    mv_cartname
    The shopping cart (default is main) to be used for this order operation.

    mv_checkout
    Page to be displayed when checkout is called from the form

    mv_failpage
    Page to be displayed on a failed order check (see Advanced Multi-level Order Pages )

    mv_nextpage
    Page to display on a return operation.

    mv_orderpage
    Page to be displayed on a refresh.

    mv_successpage
    Page to be displayed on a successful order check (see Advanced Multi-level Order Pages ).

    mv_order_profile
    Order profile to be used if the form action is submit (see Advanced Multi-level Order Pages ).

    .

    Multiple Shopping Carts

    You can maintain multiple shopping carts with MiniVend (2.02 and above). One shopping cart -- main, by name -- is defined when the user session starts. If the user orders item M1212 with the following tag:

    [order M1212 layaway] Order this item! [/order]

    the order will be placed in the cart named layaway. However, by default you won't see what you want! That is because the default shopping basket page won't display the cart you are thinking it will -- it will show the main cart. So copy the default cart (pages/ord/basket.html in the demos) to a new file, insert a [cart layaway] tag, and submit it as a MiniVend page name addendum to the cart name:

    [order M1212 layaway/lay_basket] Order this item! [/order]

    Now the contents of the layaway cart will be displayed. If you need to display a different price, you will have to emulate the [subtotal], [item-price], [item-subtotal], etc. fields with [item-list], [calc], and [currency] tags. This snippet emulates the item-price tag for a different price field layaway-price:

    [currency] [item-field layaway-price] [/currency]

    An item subtotal:

    [currency] [calc] [item-field layaway-price] * [item-quantity] [/calc] [/currency]

    A cart subtotal, using the item-list tag:

    [currency] [calc] [item-list layaway] ([item-field layaway-price] * [item-quantity]) + [/item-list] 0 [/calc] [/currency]

    The zero is needed because of the trailing plus sign left by the iterative [item-list] tag.

    Even sales tax can be emulated if you use something like a [data salestax [value state]] tag, and do some similar calculation. That is left as an exercise for the user.

    Shipping and the [nitems] tag will still work properly with a different price.

    You can also order items from a form, using the mv_order_item, mv_cartname , and optional mv_order_quantity variables.

    <FORM METHOD=POST ACTION="[process-order]"> <input type=checkbox name="mv_order_item" value="M3243"> Item M3243 <input name="mv_order_quantity" value="1"> Quantity <input type=hidden name="mv_cartname" value="layaway"> <input type=hidden name="mv_doit" value="refresh"> <input type=submit name="mv_junk" value="Place on Layaway Now!"> </FORM>

    Advanced Multi-level Order Pages

    An unlimited number of order checking profiles can be defined with the OrderProfile directive, or by defining order profiles in scratch variables. This allows a multi-level ordering process, with checking for format and validity at every stage.

    Specifications take the form of an order page variable (like name or address), followed by an equals sign and one of five check types:

    required
    A non-blank value is required

    mandatory
    Must be non-blank, and must have been specified on this form, not a saved value from a previous form

    phone
    The field must look like a phone number, by a very loose specification allowing numbers from all countries

    phone_us
    Must have US phone number formatting, with area code

    true
    Field begins with y, 1 , or t (Yes, 1, or True) - not case sensitive

    false
    Field begins with n, 0, or f (No, 0, or False) - not case sensitive

    email
    Rudimentary email address check, must have an '@' sign, a name, and a minimal domain

    Also, there are three pragmas that can be used to change behavior:.

    &fatal
    Set to '&fatal=yes' if an error should generate the error page.

    &final
    Set to '&final=yes' if a successful check should cause the order to be placed.

    &set
    Set a user session variable to a value, i.e. &set=mv_email [value email]. This is usually placed at the end after a &fatal pragma would have caused the process to stop if there was an error -- can also be used to determine pass/fail based on a derived value, as it will cause failure if it evaluates to zero or a blank value.

    As an added measure of control, the specification is evaluated for the.special MiniVend tags to provide conditional setting of order parameters. With the new [perl] [/perl] capability, quite complex checks can be done. Also, the name of the page to be displayed on an error can be set in the mv_failpage variable.

    The following file specifies a simple check of formatted parameters:

    name=required address=required city=required state=required zip=required email=required phone_day=phone_us &fatal=yes email=email &set=mv_email [value email] &set=mv_successpage ord/shipping

    The profile above only performs the &set directives if all of the previous checks have passed -- the &fatal=yes will stop processing after the check of the email address if any of the previous checks failed.

    If you want to place multiple order profiles in the same file, separate them with __END__, which must be on a line by itself.

    Simple Order Report File

    The simple order report file, ``report'', defines the layout of the order report which gets mailed on the completion of the order. For example,

    Order Date: $date Name: $name Email address: $email Shipping address: $addr Town, State, Zip: $town, $state $zip Country: $country

    Any input field from the order page can be included using the dollar sign notation.

    To prevent a value from being included in the order report, just add it to the ReportIgnore configuration directive.

    MiniVend defines some values for use in the search form -- they begin with mv_ and are automatically ignored.

    Fully-configurable Order Reports

    You can specify a fully-configurable order report by setting the hidden field ``mv_order_report'' to a legal MiniVend page. This page will be interpolated with all MiniVend tags before sending by email. The order number as set by backend ordering is in the variable mv_order_number, and available for your use.

    You could if you wish include HTML in the file, which will be interpreted by many mailers, but you can choose to use standard ASCII format. An example report is provided in the demo file <pages/ord/report.html>.

    Order Receipts

    If you specify a legal MiniVend page name in the ReceiptPage directive, the user will be sent this page instead of the default ``confirmation'' file. The file can of course be configured with all MiniVend tags, and will be interpolated for the ordered items before they are deleted from the user record. If you want to have a different receipt for different carts, set the mv_order_receipt variable in the form.

    The Order Counter

    An order counter can be enabled if the OrderCounter directive is set to a file name. An incrementing count of all orders will be kept and assigned as orders are placed. By default, the number starts at 0, but you can edit the file and change the default starting number at any time.

    This capability is made possible by the File::CounterFile module, available (as a part of the fine libwww modules) at the same place you got MiniVend. It is included with the distribution.

    Customer Input Fields

    On the order (or shopping basket) page, by default order.html, you will have a number of input fields allowing the customer to enter information such as their name and address. You can add more fields simply by putting more input elements on the order.html page, and the information will automatically be included in the order report. Input elements should be written in this way:

    <input type="text" name="town" value="[value town]" size=30>

    Choose a name for this input field such as ``email'' for an email address. Set the name attribute to the name you have chosen.

    The value attribute specifies the default value to give the field when the page is displayed. Because the customer may enter information on the order page, return to browsing, and come back to the order page, you want the default value to be what was entered the first time. This is done with the [value] element, which returns the last value of an input field. Thus,

    value="[value name]"

    will evaluate to the name entered on the previous order screen, such as:

    value="Jane Smith"

    which will be displayed by the browser.

    The size attributes specifies how many characters wide the input field should be on the browser. You do not need to set this to fit the longest possible value since the browser will scroll the field, but you should set it large enough to be comfortable for the customer.

    Product Pricing

    MiniVend maintains a price in its database for every product. The price field is the one required field in the product database -- it is necessary to build the price routines.

    For speed, MiniVend builds the code that is used to determine a product's price at catalog configuration time. If you choose to change a directive that affects product pricing you must reconfigure the catalog.

    There are several ways that MiniVend can modify the price of a product during normal catalog operation. Several of them require that the pricing.asc file be present, and that you define a pricing database. You do that by placing the following directive in catalog.cfg :

    Database pricing pricing.asc 1

    Configurable directives and tags with regard to pricing:

    • Quantity price breaks are configured by means of the PriceBreaks and MixMatch directives. They require a field named specifically price in the pricing database. The price field contains a space-separated list of prices that correspond to the quantity levels defined in the PriceBreaks directive. If quantity is to be applied to all items in the shopping cart (as opposed to quantity of just that item) then the MixMatch directive should be set to Yes.

    • Individual line-item prices can be adjusted according to the value of their attributes. See PriceAdjustment and CommonAdjust . The pricing database must be defined unless you define the CommonAdjust behavior.

    • Product discounts for specific products, all products, or the entire order can be configured with the [discount ...] tag. Discounts are applied on a per-user basis -- you can gate the discount based on membership in a club or other arbitrary means. See Product Discounts .

    For example, if you decided to adjust the price of T-shirt part number.99-102 up 1.00 when the size is extra large and down 1.00 when the size is small, you would have the following directives defined in <catalog.cfg>:

    Database pricing pricing.asc 1 UseModifier size PriceAdjustment size

    To enable the automatic modifier handling of MiniVend 3.0, you would define a size field in products.asc:

    code description price size 99-102 T-Shirt 10.00 S=Small, M=Medium, L=Large*, XL=Extra Large

    You would place the proper tag within your [item-list] on the shopping-basket or order page:

    [item-accessories size]

    In the pricing.asc database source, you would need:

    code S XL 99-102 -1.00 1.00

    As of MiniVend 3.06, if you want to assign a price based on the option, precede the number with an equals sign:

    code S M L XL 99-102 =9.00 =10 =10 =11

    IMPORTANT NOTE: Price adjustments occur AFTER quantity price breaks, so the above would negate anything set with the PriceBreaks directive/option.

    Item Attributes

    MiniVend allows item attributes to be set for each ordered item. This allows a size, color, or other modifier to be attached to a common part number. If multiple attributes are set, then they should be separated by commas. Previous attribute values can be saved by means of a hidden field on a form, and multiple attributes for each item can be stacked on top of each other.

    The configuration file directive UseModifier is used to set the name of the modifier or modifiers. For example

    UseModifier size,color

    will attach both a size and color attribute to each item code that is order

    IMPORTANT NOTE: You may not use the following names for attributes:

    item group quantity code mv_ib mv_mi mv_si

    As of MiniVend 2.02, setting the mv_separate_items or global directive SeparateItems places each ordered item on a separate line, simplifying attribute handling.

    The modifier value is accessed in the [item-list] loop with the [item-modifier attribute] tag, and form input fields are placed with the [modifier-name attribute] tag. This is similar to the way that quantity is handled, except that attributes can be ``stacked'' by setting multiple values in an input form.

    You cannot define a modifier name of code or quantity, as they are already used. You must be sure that no fields in your forms have digits appended to their names if the variable is the same name as the attribute name you select, as the [modifier-name size] variables will be placed in the user session as the form variables size0, size1, size2, etc.

    You can use the [loop item,item,item] list to reference multiple display or selection fields for modifiers (in MiniVend 3.0, you can have it automatically generated --see below). The modifier value can then be used to select data from an arbitrary database for attribute selection and display.

    Below is a fragment from a shopping basket display form which shows a selectable size with ``sticky'' setting. Note that this would always be contained within the [item_list] [/item-list] pair.

    <SELECT NAME="[modifier-name size]"> <OPTION [selected [modifier-name size] S]> S <OPTION [selected [modifier-name size] M]> M <OPTION [selected [modifier-name size] L]> L <OPTION [selected [modifier-name size] XL]> XL </SELECT>

    It could just as easily be done with a radio button group combined with the [checked ...] tag.

    MiniVend 3.0 will automatically generate the above select box when the [accessories size <code>] or [item-accessories size] tags are called. They have the syntax:

    [item_accessories attribute*, type*, field*, database*, name*] [accessories code attribute*, type*, field*, database*, name*] code Not needed for item-accessories, this is the product code of the item to reference. attribute The item attribute as specified in the UseModifier configuration directive. Typical are "size" or "color". type The action to be taken. The default is 'select', which builds an HTML select form entry for the attribute. Also recognized is 'multiple', which generates a multiple-selection drop down list, and 'show', which just shows the list of possible attributes. field The database field name to be used to build the entry (usually a field in the products database). Defaults to a field named the same as the attribute. database The database to find B<field> in, defaults to the first products file where the item code is found. name Name of the form variable to use if a form is being built. Defaults to mv_order_B<attribute> -- i.e. if the attribute is B<size>, the form variable will be named B<mv_order_size>.

    When called with an attribute, the database is consulted and looks for a comma-separated list of attribute options. They take the form:

    name=Label Text, name=Label Text*

    The label text is optional -- if none is given, the name will be used.

    If an asterisk is the last character of the label text, the item is the default selection. If no default is specified, the first will be the default. An example:

    [item_accessories color]

    This will search the product database for a field named ``color''. If an entry ``beige=Almond, gold=Harvest Gold, White*, green=Avocado'' is found, a select box like this will be built:

    <SELECT NAME="mv_order_color"> <OPTION VALUE="beige">Almond <OPTION VALUE="gold">Harvest Gold <OPTION SELECTED>White <OPTION VALUE="green">Avocado </SELECT>

    In combination with the mv_order_item and mv_order_quantity variables this can be used to allow entry of an attribute at time of order.

    If used in an item list, and the user has changed the value, the generated select box will automatically retain the current value the user has selected.

    The value can then be displayed with [item-modifier size] on the order report, order receipt, or any other page containing an [item_list].

    Product Discounts

    Product discounts can be set upon display of any page. The discounts apply only to the customer receiving them, and are of one of three types:

    1. A discount for one particular item code (key is the item-code) 2. A discount applying to all item codes (key is ALL_ITEMS) 3. A discount applied after all items are totaled (key is ENTIRE_ORDER)

    The discounts are specified via a formula. The formula is scanned for the variables $q and $s, which are substituted for with the item quantity and subtotal respectively. In the case of the item and all items discount, the formula must evaluate to a new subtotal for all items of that code that are ordered. The discount for the entire order is applied to the entire order, and would normally be a monetary amount to subtract or a flat percentage discount.

    Discounts are applied to the effective price of the product, including any quantity discounts.

    To apply a straight 20% discount to all items:

    [discount ALL_ITEMS] $s * .8 [/discount]

    To take 25% off of only item 00-342:

    [discount 00-342] $s * .75 [/discount]

    To subtract $5.00 from the customer's order:

    [discount ENTIRE_ORDER] $s - 5 [/discount]

    Perl code can be used to apply the discounts. Here is an example of a discount for item code 00-343 which prices the second one ordered at 1 cent:

    [discount 00-343] return $s if $q == 1; my $p = $s/$q; my $t = ($q - 1) * $p; $t .= 0.01; return $t; [/discount]

    If you want to display the discount amount, use the [calc] capability. This example calculates the amount of the discount for all items in the current shopping cart:

    [item_list] Discount for [item-code]: $[currency] [calc][item-field price] - [item-price 1] [/calc][/currency] [/item_list]

    Sales Tax

    MiniVend allows calculation of sales tax on a straight percentage basis, with certain items allowed to be tax-exempt. To enable this feature, the directive SalesTax is initialized with the name of a field (or fields) on the order form. Commonly, this is zipcode and/or state:

    SalesTax zip,state

    This being done, MiniVend assumes the presence of a file salestax.asc , which contains a database with the percentages. Each line of salestax.asc should be a code (again, usually a five-digit zip or a two letter state) followed by a tab, then a percentage. Example:

    45056 .0525 61821 .0725 61801 .075 IL .0625 OH .0525 VAT .15 WA .08

    Based on the user's entry of information in the order form, MiniVend will look up (for our example SalesTax directive) first the zip, then the state, and apply the percentage to the SUBTOTAL of the order. The subtotal will include any taxable items, and will also include the shipping cost if the state/zip is included in the TaxShipping directive. It will add the percentage, then make that available with the [salestax] tag for display on the order form. If no match is found, the entry 'default' is applied -- that is normally 0, but can be anything.

    If business is being done on a national basis, it is now common to have to collect sales tax for multiple states. If you are doing so, it is possible to subscribe to a service which issues regular updates of the sales tax percentages -- usually by quarterly or monthly subscription. Such a database should be easily converted to MiniVend format -- but some systems are rather convoluted, and it will be well to check and see if the program can export to a flat ASCII file format based on zip code.

    If some items are not taxable, then you must set up a field in your database which indicates that. You then place the name of that field in the NonTaxableField directive. If the field for that item evaluates true on a yes-no basis (i.e. is set to yes, y, 1, or the like), sales tax will not be applied to the item. If it evaluates false, it will be taxed.

    If your state taxes shipping, use the TaxShipping directive. Utah and Nevada are known to tax shipping -- there may be others.

    If you want to set a fixed tax for all orders, as might occur for VAT in some countries, just set the SalesTax directive to a value like tax_code, and define a variable in the user session to reflect the proper entry in the salestax.asc file. To set it to 15% with the above salestax.asc file, you would put in a form:

    <INPUT TYPE=hidden NAME=tax_code VALUE="VAT">

    or to do it without submitting a form:

    [perl values] $Safe{'values'}{tax_code} = 'VAT'; return ''[/perl]

    Using CyberCash

    MiniVend will directly interface with the Perl CCLib provided by CyberCash, Inc. This allows direct card billing at the time the order is placed. The CCLib.pm version should be 1.3 or greater. If the library is found at startup, the message ``CyberCash module found'' will be displayed.

    To use CyberCash, you must first have a CyberCash Secure Merchant Payment Server (SMPS) running on your system. It must be fully enabled, and should be tested OK with the CyberCash test suite. This capability has been tested to work with SMPS-2.1.x in mauthcapture and mauthonly modes. Any modes supported by CyberCash should work.

    The special mode minivend_test will cause the transaction to complete successfully and the information that would have been sent to the CyberCash server to be logged in the catalog error.log file.

    The CCLib.pm file must be available to MiniVend -- if you cannot install it in the main Perl library then the Minivend software directory lib/ will suffice. If it is found at MiniVend startup, a message will be displayed.

    MiniVend only will charge CyberCash in the final phase of the order process, i.e. at the time the receipt and order report are generated. The full amount as shown by the [total-cost] tag will be billed -- if you need to do partial charges you will have to manage multiple shopping carts.

    The process of enabling CyberCash processing is something like this:

    1. Turn off CreditCardAuto by setting the catalog directive to No. This would normally be done right in catalog.cfg, but it also can be done in a mv_click subroutine if you wish to mix transaction types:

      <INPUT TYPE=checkbox NAME=mv_click VALUE=CyberCash> Use CyberCash [set CyberCash] [perl config] $Safe{config}->{CreditCardAuto} = 0; $Safe{config}->{CyberCash} = 1; return ''; [/perl] mv_cyber_mode=mauthcapture [/set]

    2. Enable the CyberCash directive in catalog.cfg (or with the technique above). Also set the catalog Variable value CYBER_SECRET to the ``secret'' for your payment server. If you are not using the default values of localhost and 8000 for your server and port, set the Variables CYBER_HOST and CYBER_PORT as well. In the catalog.cfg file it would look like:

      CreditCardAuto No CyberCash Yes Variable CYBER_SECRET first-natl Variable CYBER_PORT 8000 Variable CYBER_HOST localhost

    3. Set your final order screen to accept the user form fields mv_credit_card_number (contains the actual card number), mv_credit_card_exp_month and mv_credit_card_exp_year (the expiration date month and year), and the fields containing name, address, city, state, and country. And you must define the form field mv_cyber_mode on the submitting form to enable the processing.

      The order mode must be final, either by omitting an order profile entirely or by defining an order profile that contains &final=yes.

    The fields containing name and address information should be.the same as on the standard MiniVend demo order pages:

    b_name Billing name takes priority name Shipping name used if b_name empty b_address Billing address takes priority address Shipping address used if b_address empty b_city Billing city takes priority city Shipping city used if b_city empty b_state Billing state takes priority state Shipping state used if b_state empty b_country Billing country takes priority country Shipping country used if b_country empty

    If you must use other values, they can be redefined in catalog.cfg with the Variable CYBER_REMAP like so:

    Variable CYBER_REMAP name=my_name address=my_address

    or like so:

        Variable <<EOF
        CYBER_REMAP
        b_name   my_bname
        name     my_name
        address  processed_address
        city     parsed_city
        EOF
    
    

    NOTE: As always when using the <<EOF (here document) capability, the EOF must be on a line by itself, with no leading or trailing white space. That includes carriage returns, Windows devotees. Upload in ASCII mode!

    If you have defined the directive EncryptProgram to be something containing the value pgp, then the CreditCardAuto method will be used to encrypt the mv_credit_card_number value before it is wiped from memory. (Errors in that process will be silently ignored.) It will never be written to the user session, at least by MiniVend itself, so attempts to recall it on future forms will be in vain.

    If the authorization fails, the special page failed will be displayed, and passed the CyberCash error message for display with the [subject] tag. The order will not complete, i.e. the cart will still be intact and no receipt or order report will be generated. The error itself is always available as [data session cybercash_error].

    If successful, the receipt page will be displayed, the order report emailed, and the cart will be emptied. If you wish to display the order-id returned from CyberCash on the receipt, it is available in [data session cybercash_id]. If the order is successful, but is detected as a ``success-duplicate'', [data session cybercash_error] will contain the message returned from CyberCash.


    SORTING

    MiniVend 3.03 regularizes the sorting options for sorting the search lists, loop lists, and item lists based on the contents of database fields. In addition, MiniVend 3.07 adds list slices, or limiting the displayed entries based on a start value and chunk size (or start and end value, from which a chunk size is determined). All accept a standard format sort tag which must be directly after the list call:

    [loop 4 3 2 1] [sort -2 +2] [loop-code] [/loop] [search-list] [sort products:category:f] [item-price] [item-description]<BR> [/search-list] [item-list] [sort products:price:rn] [item-price] [item-code]<BR> [/item-list] [tag each products] [sort products:category products:title] [loop-field category] [loop-field title] <BR> [/tag]

    All sort situations -- [search list] , [loop list] , [tag each table], and [item-list], take options of the form:

    [sort database:field:option* -n +n =n-n ... ]

    database
    The MiniVend database identifier. This must be supplied, and should normally be 'products' if you are using the default name for the database.

    field
    The field (column) of the database to be sorted on.

    option
    None, any, or combinations of the options:

    f case-insensitive sort (folded) (mutually exclusive of n) n numeric order (mutually exclusive of f) r reverse sort

    -n
    The starting point of the list to be displayed, beginning at 1 for the first entry.

    +n
    The number of entries to display in this list segment.

    =n-n
    The starting and ending point of the list display -- this is an alternative to -n and +n. You should specify in only one form -- if both are specified the last one will take effect.

    ...
    Don't really put ... in. This just means that you may specify as many sort levels as you wish. Lots of sort levels with large databases will be quite slow.

    Multiple levels of sort are supported, and you can cross database.boundaries on different sort levels. Cross-database sorts on the same level are not supported, so if you use multiple product databases you will have to sort with embedded Perl. This is actually a feature in some cases, since you can then display all items in a used database before or after your new ones in products .

    Examples, all based on the simple demo:

    Loop list
    [loop 00-0011 19-202 34-101 99-102] [sort products:title] [loop-code] [loop-field title]<BR> [/loop] Will display: 34-101 Family Portrait 00-0011 Mona Lisa 19-202 Radioactive Cats 99-102 The Art Store T-Shirt

    If you instead do:

    [loop 00-0011 19-202 34-101 99-102] [sort products:title -3 +2] [loop-code] [loop-field title]<BR> [/loop] you will see: 19-202 Radioactive Cats 99-102 The Art Store T-Shirt

    The tag [sort products:title =3-4] is equivalent to the above.

    Search list
    A search of all products (i.e. http://yoursystem.com/cgi-bin/simple/scan/ra=yes):

    [search-list] [sort products:artist products:title:rf] [item-field artist] [item-field title]<BR> [/search-list] will display: Gilded Frame Grant Wood American Gothic Jean Langan Family Portrait Leonardo Da Vinci Mona Lisa Salvador Dali Persistence of Memory Sandy Skoglund Radioactive Cats The Art Store The Art Store T-Shirt Vincent Van Gogh The Starry Night Vincent Van Gogh Sunflowers

    Note the reversed order of the title for Van Gogh, and the presence of the accessory item Gilded Frame at the front of the list (it has no artist field, and as such sorts first).

    Adding a slice option:

    [search-list] [sort products:artist products:title:rf =6-10] [item-field artist] [item-field title]<BR> [/search-list] will display: Sandy Skoglund Radioactive Cats The Art Store The Art Store T-Shirt Vincent Van Gogh The Starry Night Vincent Van Gogh Sunflowers

    If the end value/chunk size exceeds the size of the list, only the elements that exist will be displayed, starting from the start value.

    Shopping cart
    [item-list] [sort products:price:rn] [item-price] [item-code]<BR> [/item-list] will display the items in your shopping cart sorted on their price, with the most expensive shown first. (Note that this is based on the database field, and doesn't take quantity price breaks or discounts into effect.) B<NOTE:> You cannot sort on modifier values or quantities.

    Complete database contents
    [tag each products] [sort products:category products:title] [loop-field category] [loop-field title] <BR> [/tag]

    A two level sort, that will sort products based first on their category then on their title within the category.

    Note that large lists may take some time to sort -- if you have a product.database with many thousands of items, it is not recommended that you use the [tag each products] sort unless you are planning on caching or statically building your pages.


    SHIPPING

    MiniVend allows the addition of a flat shipping charge with the Shipping directive. Most catalogs have more elaborate requirements, requiring use of the SHIPPING capability of MiniVend.

    To enable custom shipping, enter the default field to use in the CustomShipping directive:

    CustomShipping weight

    IMPORTANT NOTE: Before MiniVend 2.0, there could only be one field used to set the criteria. As of MiniVend 2.0, the entry in the shipping file which is exactly the same as the value of the mv_shipmode variable will be used to determine the field criteria for the shipping method. This allows weight to be used for one mode, while price or quantity is used for another. The CustomShipping directive only sets the default field to be used if none is present in the mode specification.

    Default Shipping Mode

    If a default shipping mode other than default is desired, enter it into the DefaultShipping directive:

    DefaultShipping UPSG

    This will make the entry on the order form checked by default when the user starts the order process, if it is put in the form:

    <INPUT TYPE=RADIO NAME=mv_shipmode VALUE=upsg [checked mv_shipmode upsg]>

    To force a choice by the user, you can make mv_shipmode a required form variable (with RequiredFields or in an order profile) and set DefaultShipping to zero.

    Shipping Cost Database

    The shipping cost database (located in ProductDir/shipping.asc) is a tab-separated ASCII file with six fields -- code, text description, criteria (quantity or weight, for example), minimum number, maximum number, and cost. None of the fields are case-sensitive. It always needs to be present if CustomShipping is to be used.

    code
    The unique identifier for that shipping method and criteria range.

    description
    Text to describe the method (can be accessed on a page with the [shipping_description] element).

    criteria
    Whether shipping is based on weight, quantity, price, etc. Valid MiniVend tags can be placed in the field to do a dynamic lookup -- if a number is returned, that is used as the accumulated criteria -- that is, the total of weight, quantity, or price as applied to all items in the shopping cart.

    The criteria field varies according to whether it is the first field in the shipping file exactly matching the mode identifier. In that case, it is called the main criterion. If it is in subsidiary shipping lines matching the mode (with optional appended digits) then it is called a qualifying criterion. The difference is that the main criterion returns the basis for the calculation (i.e. weight or quantity) while the qualifying criterion determines whether the individual line may match the conditions.

    The return must be one of:

    o quantity
    quantity -- The literal value quantity as the main criterion will simply count the number of items in the shopping cart and return it as the accumulated criteria.

    o <field name>
    A valid product database field (column) name as main criterion will cause the number of items in the shopping cart to be multiplied by the value of the field for each item to obtain the accumulated criteria.

    o n.nn
    where n.nn is any number. It will be directly used as the accumulated criteria. This can be effectively returned from a Perl subroutine or MiniVend [calc][item-list] ... [/item-list][/calc] to create custom shipping routines.

    IMPORTANT NOTE: The above only applies to the first field that.matches the shipping mode exactly. Following criteria fields contain qualifier matching strings.

    minimum
    The low bound of quantity/weight/criteria this entry applies to.

    maximum
    The high bound of quantity/weight/criteria this entry applies to. The first found entry is used in case of ties.

    cost
    The total cost, determined by formula if it begins with f, by multiplier if it begins with x, by UPS-style lookup if it begins with u, by named subroutine if it begins with an s, and a straight cost otherwise. If it begins with an e, a zero cost is returned with the following string as the error message.

    The cost is calculated like this:.

    1. The base code is selected by reading the value of mv_shipmode in the user session. If it has not been explicitly set, either by means of the DefaultShipping directive or by setting the variable on a form (or in an order profile), it will be default.

    2. The criterion field is found -- if it is quantity, then it is the total quantity of items on the order form. If it is any other name, then the criterion is calculated by multiplying the return value from the product database field for each item in the shopping cart, multiplied by its quantity. (If the lookup fails due to the column or row not existing, a zero cost will be returned, and an error is sent to the catalog error log.) If a number is returned from a MiniVend tag, then that number is used directly.

    3. Entries in the shipping database that begin with the same string as the shipping mode are examined. If none is found, a zero cost is returned and an error is sent to the catalog error log.

      NOTE: You may use the same mode name for all lines in the same group, but the first one will contain the main criteria.

    4. The value of the accumulated criteria is examined, and if it falls with in the minimum and maximum, the cost is then applied.

    5. If the cost is fixed, it is simply added.

    6. If the cost field begins with an x, the cost is multiplied by the accumulated criterion -- price, weight, etc.

    7. If the cost field begins with f, the formula following is applied. Use @@TOTAL@@ as the value of the accumulated criterion.

    8. If the cost field begins with u, a UPS lookup is done.

    9. If the cost field begins with s, a Perl subroutine call is made.

    10. If the cost field begins with e, zero cost is returned and an error placed in the session ship_message field, available as [data session ship_message]. (If using the standard tag syntax, you should surround it with [post] [/post] to ensure you get the messages from the current page.)

    Here is an example shipping file using all of the methods of.determining shipping cost.

    NOTE: The columns are lined up for your reading convenience, the actual entries should have ONE tab between fields.

    rpsg RPS quantity 0 0 0 rpsg RPS quantity 1 5 7.00 rpsg RPS quantity 6 10 10.00 rpsg RPS quantity 11 150 x .95 usps US Post price 0 0 0 usps US Post price 1 50 f 7 + (1 * @@TOTAL@@ / 10) usps US Post price 50 100 f 12 + (.90 * @@TOTAL@@ / 10) usps US Post price 100 99999 f @@TOTAL@@ * .05 upsg UPS weight [value state] 0 0 e Nothing to ship. upsg UPS AK HI 0.1 150 u upsg [value zip] 12.00 round upsg UPS 0.1 150 u upsg [value zip] 2.00 round upsg UPS 150 9999 e @@TOTAL@@ lb too heavy for UPS fedex FedEx quantity 1 9999 s fedex_cost ;[value country]

    • If the user selected RPS, (code rpsg), and the quantity on the order was 3, the cost of 7.00 from rpsg1 would be applied. If the quantity were 7, the next entry from rpsg2 would be selected, for a cost of 10.00. If the quantity were 15, rpsg3 would be selected, and the quantity of 15 multiplied by 0.95, for a total cost of 14.25.

    • The second one, usps, is a more complicated formula -- using price as the criteria. If the total price of all items in the shopping cart (same as [subtotal] without quantity price breaks in place) is from 1 to 50, the cost will be 7.00 plus 10% of the order. If the total is from 50.01 to 100, the cost will be 12.00 plus 9% of the order total. If the cost is 100.01 or greater, then 5% of the order total will be used as the shipping cost.

    • The third, upsg, is a special case. It specifies a UPS lookup based on your UPS zone and two required values (and two optional arguments):

      1. Weight (careful, always use weight for this one!) 2. The zip/postal code of the recipient, of which only the first three digits are used. 3. A fixed amount to add to the cost found in the UPS tables (use 0 as a placeholder if specifying roundup) 4. If set to 'round', will round the cost up to the next integer monetary unit.

      If the cost returned is zero, the reason will be placed as an error message in the session variable ship_message (available as [data session ship_message]).

      UPS weights are always rounded up if any fraction is present.

      The routines use standard UPS lookup tables. First, the UPS Zone file must be present. That is a standard UPS document, specific to your area, that you must obtain from UPS and enter into and make available to MiniVend in TAB-delimited format. (As of March 1997, you can use the standard .csv file distributed by UPS on their web site at www.ups.com.) You specify it with the UpsZoneFile directive -- it is usually named something like NNN.csv, where NNN is the first three digits of the originating zip code.

      Second, you must obtain the cost tables from UPS (again, you can get them from www.ups.com) and place them into a MiniVend database. That database, its identifier specified with the first argument (upsg in the example) of the cost specification, is consulted to determine the UPS cost for that weight and rate schedule.

      You can append a simple shipping cost qualification to a UPS lookup. If any additional parameters are present after the five usual ones used for UPS lookup, they will be interpreted as a Perl subroutine call. The syntax is the same as if it was encased in the tag [perl sub] [/perl], but the following substitutions are made prior to the call:

      @@COST@@ is replaced with whatever the UPS lookup returned @@GEO@@ is replaced with the zip (or other geo code) @@ADDER@@ is replaced with the defined adder @@TYPE@@ is replaced with the UPS shipping type @@TOTAL@@ is replaced with the total weight

      The example above also illustrates geographic qualification. If the value of the form variable state on the checkout form is AK or HI, the U.S. states Alaska and Hawaii, a $10.00 additional charge (over and above the normal 2.00 handling charge) is made. This can also be used to select on country, product type, or any other qualification that can be encoded in the file.

    • The last entry, fedex, uses a named subroutine. The example is designed to work with this subroutine defined in catalog.cfg:

          Sub <<EOF
          sub fedex_cost {
              my($country) = @_;
              my $cost;
              if($country =~ /^usa?$/i) {
                  $cost = 20;
              }
              else {
                  $cost = 50;
              }
              return $cost;
          }
          EOF
      
      

      NOTE: The text above appears indented, but in the catalog.cfg file it must begin at the beginning of the line. Also, make sure you upload in ASCII mode -- carriage returns are not tolerated.

      It will simply return a cost of 20 if the country the user has entered is US or USA -- and return 50 otherwise. Obviously much more complicated routines can be defined. Read the following only if you know Perl well and/or are not of faint heart.

      You can call named subroutines with any of the methods, defined with [set name] your_perl_code_here [/set], Sub , or GlobalSub .

      If parameters are specified, separated by commas, they will be taken as either fixed values or as database fields to be sent to the subroutine in an anonymous hash keyed on the item code (for each item in the *current* shopping cart).

      If a database other than the products database is to be used, the database name should be prepended with a colon (:) separator. If a key other than the item code is to be used, it should be appended with a semi-colon separator.

      To send fixed value to the subroutine (appended to the call reference as an array of fixed scalar parameters), begin the parameter with a semicolon. They will be appended globally after the hash reference.

      Examples

      # Sends the weight of each item from the products database weight # Sends the value of the handling field from the # special database for each item special:handling # Sends the value of the 'adder' field from the special # database, for the value the user has entered for 'country' # The spaces around the separators are OK special : adder ; [value country] # Sends a fixed parameter of 20 to the subroutine ;20

      The parameters are interpreted for MiniVend tags before being parsed. Here is a complete example:

      s item_cost weight,modes:[value mv_shipmode];[value country], ;20, ;25 items in the shopping cart: 00-0011 19=202 ------- product database ---- code weight description price 00-0011 8 The Mona Lisa 1000 19-202 12 American Gothic 800 ------- modes database ---- code upsg upsb upsr postal_air postal_surface ` UK 0 0 0 1 1

      will call the subroutine item_cost, and will send the weight of each item, along with the value of the modes database column corresponding to the shipping mode the user has selected, keyed with the value of country on their order form. If the user has selected mode postal_air, and is in the country coded as UK, the subroutine will be called as if it was:

      item_cost( { '00-0011' => {postal_air => '1', weight => '8'}, '19-202' => {postal_air => '1', weight => '12'}, }, 20, 25 )

      If the undefined value is returned by the routine, the next shipping mode will be tried. If a non-numeric string value is returned, its value will be placed as an error message in the session variable ship_message (available as [data session ship_message]) and a zero cost will be returned. If any number or the empty string is returned, it will be used as the shipping cost (even 0).

    .

    Determining shipping modes

    MiniVend 3.07 and above uses the CustomShipping and Shipping directives to determine the shipping characteristics based on geography or other session qualifier.

    You can specify user variables to examine for geographic offering of shipping modes with the CustomShipping directive, and you can specify which qualifications they must meet with the Shipping directive. Example:

    CustomShipping state country Shipping _us_a modes "upsb upsr usps" Shipping _us_a state "AK HI" Shipping _us_b modes "upsg upsb upsr usps" Shipping _us_b country "upsg upsb upsr usps" Shipping euro_b modes "surfint_b surfair_b" Shipping euro_b country "surfint_b surfair_b" Shipping euro_b modes "surfint_b surfair_b"

    This means the MiniVend will first examine the

    Geographic qualification

    If the return value in the main criterion includes whitespace, the remaining information in the field is used as a qualifier for the subsidiary shipping modes. This can be used to create geographic qualifications for shipping, as in:

    upsg UPS Ground weight [value state] 0 0 e No items selected upsg UPS Ground AK HI 0.1 150 u Ground [value zip] 12.00 upsg UPS Ground 0.1 150 u Ground [value zip] 3.00

    Handling charges

    Additional handling charges can be defined in the shipping file by setting the form variable mv_handling to a space, comma, or null-separated set of valid shipping modes. The lookup and charges are done in the same fashion, and the additional charges are added to the order. (The user is responsible for displaying the charge on the order report or receipt with a [shipping handling] tag or the like.) All of the shipping modes found in mv_handling will be applied -- if multiple instances are found on a form, the accordingly null-separated values will all be applied. Careful! This should not be done in an item-list unless you take care to account for multiple setting of the variables.

    If you wished only to process a handling charge once, you could do safely:

    [item-list] [if-field very_heavy] [perl values] return '' if $Safe->{'values'}->{mv_handling} =~ /very_heavy/; return "<INPUT TYPE=hidden NAME=mv_handling VALUE=very_heavy>"; [/perl] [/if-field] [/item-list]

    A non-blank/non-zero value in the database field very_heavy will then trigger Perl code which will only set mv_handling once.


    TRACKING AND BACKEND ORDER ENTRY

    MiniVend allows the entry of orders into a system via one of several methods. The AsciiBackend capability allows submittal of parameters to an external order entry script. Support for SQL allows entry of orders directly into an SQL database. Orders can be written to an ASCII file. They can be formatted precisely for email-based systems. The orders can be placed in a DBM file. Finally, embedded Perl allows completely flexible order entry, including real-time credit-card verification and settlement.

    Easy ASCII Tracking

    If you set AsciiTrack to a legal file name (based in VendRoot unless it has a leading ``/''), a copy of the order will be saved there as well as being emailed.

    If you set AsciiBackend to a legal file name (based in VendRoot unless it has a leading ``/''), it will save the backend fields defined in BackendOrder along with the item-code and quantity of items being ordered. The fields are separated by TAB characters.

    For either directive, if the file name string begins with a pipe ``|'', a program will be run and the output ``piped'' to that program. This allows easy backend entry of orders with an external program.

    SQL Tracking

    See the [sql set] tag for an example of entering orders in an SQL database.


    SSL SECURITY

    MiniVend has several features that enable secure ordering via SSL (Secure Sockets Layer). Despite their mystique, SSL servers are actually quite easy to operate. The difference between the standard HTTP server and the SSL HTTPS server, from the standpoint of the user, is only in the encryption and the specification of the URL -- https: is used for the URL protocol specification instead of the usual http: designation.

    IMPORTANT NOTE: MiniVend attempts to perform operations securely, but no guarantees or warranties of any kind are made! Since MiniVend comes with Perl source, it is possible to modify the program to create bad security problems. One way to minimize this possibility is to record digital signatures, using MD5 or PGP, of minivend, minivend.cfg , and all modules included in minivend. Check them on a regular basis to ensure they have not been changed.

    MiniVend uses the SecureURL directive to set the base URL for secure transactions, and the VendURL directive for normal non-secure transactions. Secure URLs can be enabled for forms through the [process_target action secure] element.

    MiniVend incorporates additional security for credit card numbers. Any field on the order form which has credit_card in its name will not be written to disk unless it is encrypted. An external encryption program, such as pgp(1) or des(1) can be used.

    NOTE: The internal Des encryption mode is no longer supported in MiniVend 2.02 and higher. Try PGP instead -- it is more secure and easier to use.

    To accept credit_card fields, you need to define the directive CreditCardAuto to yes. EncryptProgram also needs to be defined with some value, one which will, with hope, encrypt the number. PGP is now recommended above all other encryption program. The entries should look something like:

    CreditCardAuto Yes EncryptProgram /usr/local/bin/pgp -feat sales@company.com

    See CreditCardAuto for more information on how to set the form variables.

    Administrative Pages

    With MiniVend's GlobalSub capability, very complex add-on schemes can be implemented with Perl subroutines. And with the new writable database, pages that modify the catalog data can be made. If you mark a page as an AdminPage , only the catalog administrator may use it.

    In addition, you can create a file in any MiniVend page subdirectory called .access. If that file is present and non-zero in size, any pages in that directory are only available to users who have the REMOTE_USER CGI variable set (which means they have given a user name and password, ala normal HTTP Basic Authorization). This is a way to provide ``subscription-only'' pages that are only available to logged-in users.


    CONTROLLING PAGE APPEARANCE

    Using Frames

    MiniVend fully supports frames, the proposed extension to HTML 3.0. (Currently only Netscape 2.0 and above browsers support frames.) Frames significantly enhance the electronic catalog experience, since the user can maintain a context -- with a search frame, a product details frame, a table-of-contents frame, etc. The demo included with MiniVend is based on frames, though if you access it with a non-frame browser it will operate perfectly well.

    Frames are accessed by adding a TARGET element to a HREF, naming the frame that the referenced URL should be placed in. MiniVend produces targets with the pagetarget and areatarget elements, which send target tags if frames are enabled (by a [frames_on] element. Any frame name can be used, including the special frames of _top, _blank, _parent, and _self.

    As shown in the demo pages, the best way to accommodate both types of browsers is by having an index.html page that sets the beginning frame set. The <FRAMESET> and <FRAME> tags will be ignored by standard browsers, which will read the HTML between the <NOFRAMES> and </NOFRAMES> tags below.

    The format of the first set of URLs passed to the frames is important - only ONE MiniVend link must be called. That sets the session ID for the user. If two URLs were called, MiniVend would assign two session IDs to the user, scrambling the context of their navigation. From this single access, all further references to MiniVend are made, though after the first access multiple frame targets can be referenced.

    This first MiniVend page that is accessed (with a frame browser) should contain a [frames_on] element. It is the only page that need (or should) contain a [frames_on], which is persistent throughout the session. This page should never be seen by a non-frame browser.

    Subsequent accesses to MiniVend URLs will now contain the proper session information, and as long as pagetarget or page elements are used to pass the URLs, context will be maintained.

    Here are the frames-specific tags:

    [frames_on]
    Turns on the frames processing option, which is disabled by default. The proper way to use this is to put it ONLY in the first page which is loaded by frame-based browsers, as part of the initial frame load. It is persistent for the entire session, or until counteracted with a [frames_off] tag.

    [frames_off]
    Turns off the frames processing option. This can be used to disable frames, perhaps as a clickable option for users. It is persistent for the entire session, or until counteracted with a [frames_on] tag.

    IMPORTANT NOTE: This doesn't turn of frames in your browser! If you let a TARGET tag escape, it will probably cause a new window to be opened, or other types of anomalous operation.

    [pagetarget pg frame arg*]
    (new syntax [page href=``dir/page'' target=``frame'' arg=``argument''])

    Same as the page element above, except it specifies an output frame to target if frames are turned on. The name is case-sensitive, and if it doesn't exist a new window will be popped up. This is the same as the [page ...] tag if frames are not activated. For example, [pagetarget shirts main] will expand into a link like <a href=``http://machine.company.com/cgi-bin/vlink/shirts?WehUkATn;;1'' TARGET=``main''>. The catalog page displayed will come from shirts.html in the pages directory, and be output to the main frame. Be careful, frame names are case-sensitive.

    The optional arg is used just as in the page tag.

    [areatarget pg frame arg*]
    (new syntax [area href=``dir/page'' target=``frame'' arg=``argument'']

    Inserts a Vend URL in a format to provide a targeted reference for a client-side imagemap. You set up the <AREA> tag with:

    <AREA COORDS="220,0,270,20" HREF="[areatarget page frame]">

    If frames are enabled, this will expand to:

    <AREA COORDS="220,0,270,20" HREF="http://machine.company.com/vlink/page?ErTxVV8l;;38" TARGET="frame">

    If frames are not enabled, this will expand to:

    <AREA COORDS="220,0,270,20" HREF="http://machine.company.com/vlink/page?ErTxVV8l;;38">

    The optional arg is used just as in the page tag.

    [framebase name]
    Outputs a <BASE FRAME=``name''> tag only if MiniVend is in frames mode. It should be used within the HTML <HEAD> section.

    .

    Changing output frame in a form

    If you want to send output to different frames based on input from the user, you can set the mv_change_frame variable. If found in the current form, a Window-Target: header will be sent to route the HTML output to the frame named in mv_change_frame.

    You can use One-click Multiple Variables to set the target if you wish.

    <INPUT TYPE="submit" name="mv_todo" value="Search"> <INPUT TYPE="submit" name="mv_click" value="Continue Shopping"> [set Continue Shopping] mv_todo=return mv_nextpage=browse mv_change_frame=_top [/set]

    The above snippet will, when placed in a MiniVend form, send the output of a Search submission to the current default frame, but when Continue Shopping is selected the output will will go to the page browse.html with the page routed to the top level frame for the current browser window.

    If you are setting a target with the [process_target target] tag, you will either have to make that target none or set the scratch variable mv_ignore_frame on the page at time of display. Either will prevent conflicting window targets from being sent.

    Body and Buttonbar Control

    MiniVend provides centralized page color and imagemap control through use of the [body n] and [buttonbar n] elements. It also can place a random message from a series of messages with the [random] element, and embed help messages with the [help item] element.

    The [body n] element selects a color scheme -- numbered from 1 to 15 -- that is set by the Mv_Background, Mv_TextColor, Mv_BgColor, Mv_LinkColor, and Mv_VlinkColor directives. Each can contain up to 15 parameters, after an opening BEGIN. Here is an example:

    Mv_Background BEGIN /images/blue_pap.gif Mv_BgColor BEGIN none steelblue white Mv_LinkColor BEGIN none white black Mv_TextColor BEGIN none ltgreen blue Mv_VlinkColor BEGIN none orange purple

    The above sequence set in the catalog.cfg file, defines three color schemes, accessed with [body 1], [body 2], and [body 3] elements in MiniVend pages. The first scheme uses the file /images/blue_pap.gif as the background pattern, and keeps the user's default colors for everything else. It is called by a [body 1] element, which when expanded becomes <BODY BACKGROUND="/images/blue_pap.gif>.

    The second scheme defines no background pattern (there is only one file in the Mv_Background directive), but defines a background color of steelblue, with a text color of white, a link color of light green, and a visited link color of orange. It is accessed by the [body 2] element, which when expanded becomes <BODY BGCOLOR=``steelblue'' TEXT=``white'' LINK=``ltgreen'' VLINK=``orange''>.

    The third color scheme is similar to the second, except defines white-black-blue-purple for the four colors. It is accessed with a [body 3] element.

    If there is no defined scheme for a body element (as there wouldn't be if you put [body 4] in a page with the above schemes defined) MiniVend simply outputs a standard <BODY> tag.

    The user can also define their own colors if the Mv_customcolors variable is set (upon a form submission). See the supplied control.html page for an example of how to set custom colors.

    Image maps can be supplied and similarly controlled with the [buttonbar n] series of tags. They are defined with the ButtonBars directive in catalog.cfg, and take the form of a series of file names in MiniVend format -- i.e., relative to the PageDir and without a .html extension. To use the buttonbars, create a file with an IMG directive set with the USEMAP element and an associated client-side image map (defined with <MAP> </MAP>. The [areatarget] or [area] tags are used to set the URLs. An example:

    <IMG SRC="/sample/images/artbar0.gif" USEMAP="#ARTBAR0"> <MAP NAME=ARTBAR0> <AREA COORDS="198,0,278,20" HREF="[areatarget fr_sel search]"> <AREA COORDS="303,0,363,20" HREF="[areatarget fr_search search]"> <AREA COORDS="388,0,442,20" HREF="[areatarget fr_greet main]"> <AREA COORDS="473,0,537,20" HREF="[areatarget control main]"> <AREA COORDS="0,0,560,20" NOHREF> </MAP>

    If the above were saved in the file PageDir/bars/artbar0.html (where PageDir is your MiniVend pages directory), you would be able to access this imagemap in your pages with a [buttonbar 0] tag, at least after MiniVend read this line in the configuration file:

    ButtonBars bars/artbar0 bars/artbar1 bars/artbar2

    The above entry allows you to define three imagemaps and access them in your pages simply as [buttonbar 0], [buttonbar 1], and [buttonbar 2]. The advantage of this scheme is central definition of a series of button bars with only a few tags -- if you change your page colors or mapping, you need only change one file and the change will roll over to all of your catalog pages. Since some installations can number in the thousands of catalog pages, using the pre-defined buttonbars can save a lot of editing. (Server-side includes cannot be used to achieve the same thing with MiniVend, since they wouldn't have the proper URLs.)

    Integrated Image Maps

    Imagemaps can also be defined on forms, with the special form variable mv_todo.map. A series of map actions can be defined -- the action specified in the default entry will be applied if none of the other coordinates match. The image is specified with a standard HTML 2.0 form field of type IMAGE. Here is an example:

    <INPUT TYPE="HIDDEN" NAME="mv_todo.map" VALUE="rect submit 0,0 100,20"> <INPUT TYPE="HIDDEN" NAME="mv_todo.map" VALUE="rect cancel 290,2 342,18"> <INPUT TYPE="HIDDEN" NAME="mv_todo.map" VALUE="default refresh"> <INPUT TYPE="IMAGE" NAME="mv_todo" SRC="url_of_image">

    All of the actions will be combined together into one image map with NCSA-style functionality -- see the NCSA imagemap documentation for details -- except that MiniVend form actions are defined instead of URLs. The standard actions are:

    submit Submit order refresh Refresh order page (update quantities, etc.) cancel Cancel order and wipe credit card numbers return Go to previous page (or page defined in mv_nextpage variable) control Control help, colors, etc. search Search for an item in the catalog

    Random Banners

    The [random] element, in conjunction with the Random directive in the catalog.cfg file, is similar to the buttonbar tag, except it displays random messages or images. It can be used to place a random tip, hint, ad, or message, and can be any legal HTML construct.

    Rotating Banners

    The [rotate] element, in conjunction with the Rotate directive in the minivend.cfg file, is similar to the random tag, except it displays messages or images guaranteed to be presented to the user in a specific order. It can be used to place a tip, hint, ad, or message, and can be any legal HTML construct.

    In-line Help

    The [help tag] element, in conjunction with the Help directive in the minivend.cfg file, is similar to the buttonbar tag, except it displays help messages or images, and is keyed by item name. The help can be contained in any of a series of files defined in the Help directive. It can contain most MiniVend elements. The user can turn off help through a form -- see the control.html file for an example.


    STATIC PAGE BUILDING

    MiniVend now has a complete implementation of a static page building facility. It allows you to build a parallel page tree completely in HTML, and most importantly, keeps track of all of the URLs for you. It means that MiniVend, whether the page on the browser was called dynamically or statically, will call the appropriate page for you. This can mean huge performance gains in catalogs with lots of pages in the browsing structure, for any statically built pages never have to call MiniVend. This improves performance and decreases server load.

    You can also use it to build page trees that are scannable by a search engine spider.

    As of MiniVend 3.03, to make static page building active, you must set the Static directive to Yes. This allows you to turn it on or off with a single directive, and is a change from MiniVend 3.02 and below.

    It is invoked when starting the MiniVend server by passing the extra parameters -build shop to the minivend program. MiniVend will scan the entire page structure, testing each page to see if it has any dynamic elements. Dynamic elements are those MiniVend tags which depend on user session status, like the contents of the shopping cart, conditional tests on user variables, or databases marked as dynamic with the DynamicData directive. If a page has dynamic elements, it will not be built statically.

    Some tags which cause static building to fail are:

    [cart ...] [if session ...] [perl] [checked ...] [if validcc ...] [salestax] [data ...]* [if value ...] [scratch ...] [default ...] [item_list] [selected ...] [discount] [last_page] [shipping] [finish-order] [lookup ..] [shipping_desc] [frames_on|off] [loop-data ...]* [sql set] [if data ...]* [loop-field ...]* [subtotal] [if discount ...] [sql set] [total_cost] [if items ...] [nitems] [value ...] [if scratch ...] [perl] * Only if database referenced is dynamic

    In addition, if a [search_list] references dynamic items, it will also prevent a search from being cached or built statically.

    Pages are also searched for static [page scan/...] searches, and those searches are built statically if appropriate. They are placed in the pages scan1.html on up, so don't name any of your pages scan and then digits if you want to avoid clashing. Search builds recurse one level down, meaning that if you have a category search that yields more category searches, they will also be built. You can set the recursion with StaticDepth -- the default is two.

    A page marked as an AdminPage or NoCache will not be statically built or cached.

    If you wish a page to build statically anyway, despite the presence of dynamic elements, you can insert [tag flag build][/tag] at the top of the page. This tells the builder to ignore dynamic elements and build the page anyway -- it will not override NoCache or AdminPage.

    Additionally if you pass a name with [tag flag build]name[/tag], a symbolic link to name will be made in StaticDir . This allows named pages to be reliably found -- otherwise the name of the page varies with the order the search is found. Commonly you would use [tag flag build][value mv_searchspec][/tag] to build a link based on the search string.

    Pages are marked for static build in one of three ways:

    • If you want all pages to be statically built when possible, set the catalog.cfg directive StaticAll to yes. MiniVend will scan all pages and see if they can be built. If you have pages and/or directories which you don't want scanned, use the NoCache directive to disable it.

    • If you want only certain pages to be statically built, you can either individually mark each one with the StaticPage directive, or you may set a StaticPattern which encompasses pages to be built statically.

    • You can place a list of pages in the file .build in the root of the pages directory. MiniVend will use that as the list of pages to be built on this run.

    In addition, you can build all possible on-the-fly pages out of the.database if the StaticFly directive is set. This is subject to the StaticPattern as well, so you could build only a portion of the database if you wished. Obviously catalogs that have many thousands of items should be careful about use of StaticFly .

    The names of pages that are statically built are maintained in the file .static, located in the MiniVend PageDir . This is how MiniVend knows which pages should be referenced with static URLs.

    Any pages included in the list(s) that fail due to dynamic elements have their names placed in the file .unbuilt after the build process.

    The StaticDir directive defines the file path to the root of the page structure that will be built. If blank, it will use the directory static in the catalog root, which can then be copied to the appropriate place in HTML document space.

    WARNING: Any existing files that are present may be removed from this directory! Do not place normal pages there!

    The StaticPath directive defines the URL path to the root of the page structure that will be built. It is relative to HTTP document root, and must obviously be the URL path to StaticDir . Default is /, or DocumentRoot.

    The StaticSuffix directive defines the suffix of the files that will be built. The default is .html. DOSites might want to make it .htm, and if you wished to have the files parsed for server side includes you might use .shtml.

    If you wish to build the catalog pages offline (recommended on servers that are used by multiple catalogs), you can use the command:

    start -test -build shop

    where shop is the name of the catalog to be built. (Multiple -build name directives can be used to build more than one catalog.)


    INTERNATIONALIZATION

    MiniVend 3.07 adds a rich set of I18N features to allow conditional message display, differing price formats, different currency definitions, price factoring, sorting, and other settings.

    The definitions are maintained in the catalog.cfg file through the use of built in POSIX support and MiniVend's Locale directive.

    All settings are independent for each catalog and each user of that catalog -- you can have customers accessing the same catalog in any of an unlimited number of languages and currencies.

    Setting the locale

    The locale could be set to fr_FR (French for France) in one of two ways:

    [set mv_locale]fr_FR[/set]
    Set the locale by placing a [set mv_locale]fr_FR[/set] in the first page which introduces the locale settings. Every page AFTER that page will have the settings in effect.

    [page /process/locale/fr_FR/page/catalog]
    This is the same as [page catalog], except when the link is followed it will set the locale to fr_FR before displaying the page.

    Once the locale is set for that user, it is in effect for the duration.of their session.

    MiniVend Locale Settings

    The Locale directive has many possible settings, allowing complete internationalization of page sets and currencies. The Locale directive is defined in a series of key/value pairs, with a key (which contains word characters only) followed by a value. The value should be surrounded with double quotes if it contains whitespace. In this example, the key is Value setting.

    Locale fr_FR "Value setting" "Configuration de valeur" Locale de_DE "Value setting" Werteinstellung

    When accessed via the special tag [L]Value Setting[/L], the value Configuration de valeur will be displayed only if the locale is set to fr_FR. If the locale is set to de_DE, the string Werteinstellung will be dislayed. If it is neither, the default value of Value Setting will be displayed.

    The L and /L must be capitalized -- this is done for speed of processing as well as easy differentiation in text.

    For longer series of strings, the configuration file recognizes:

        Locale fr_FR <<EOF
            {
                    ``Value setting'',
                    ``Configuration de valeur'',
                    "Search",
                    "Recherche"
            }
            EOF
    
    

    The above sets two string substitutions. As long as this is valid Perl syntax describing a series of settings, the text will be matched. It can contain any arbitrary set of characters that don't contain [L] and [/L]. If using double quotes, string literals like \n and \t are recoginzed.

    The [L]default text[/L] is set before any other page processing. It is equivalent to the characters ``default text'' or the appropriate Locale translation for all intents and purposes. Minivend tags and Variable values can be embedded.

    You will need to be quite careful in editing pages with localization information. Changing even one character of the message will change the key value and invalidate the message for other languages. To prevent this, you can instead use:

    [L key]The default.[/L]

    The key msg_key will then be used to index the message. This may be preferable for many applications.

    A localize script is included with minivend. It will parse files included on the command line and produce output that can be easily edited to produce localized information. Given an existing file, it will merge new information where appropriate.

    Special Locale keys for price representation

    MiniVend honors the standard POSIX keys:

    mon_decimal_point decimal_point mon_thousands_sep thousands_sep currency_symbol int_currency_symbol frac_digits p_cs_precedes

    See the POSIX setlocale(3) man page for more information.

    These will be used for formatting prices and will approximate the number format used in most countries. To set the price format to something that is exactly how you want it, you can use the special keys:

    price_picture
    MiniVend will format a currency number based on a ``picture'' given to it. The basic form is:

    Locale en_US price_picture "$ ###,###,###.##"

    This is the presumably for locale en_US, the United States, and it would display 4452.3 as $ 4,445.30.

    The same display can be achieved with:

    Locale en_US mon_thousands_sep , Locale en_US mon_decimal_point . Locale en_US p_cs_precedes 1 Locale en_US currency_symbol $

    A common price_picture for European countries would be ###.###.###,##, which would display the same number as 4.452,30. To add a franc notation at the end for the locale fr_FR, you would use the setting:

    Locale fr_FR price_picture "##.###,## fr"

    IMPORTANT NOTE: The decimal point in use, set by mon_decimal_point, and the thousands separator mon_thousands_sep must match the settings in the picture. The frac_digits setting is not used in this case -- it is derived from the location of the decimal (if any).

    The same setting for fr_FR above can be achieved with:

    Locale fr_FR mon_thousands_sep . Locale fr_FR mon_decimal_point , Locale fr_FR p_cs_precedes 0 Locale fr_FR currency_symbol fr

    If the number of digits is greater than the # locations in the picture, the digits will be changed to asterisks. An overflow number above would show as **.***,** fr.

    picture
    Same as price_picture , but sets the value returned if the [currency] tag is not used.

    If the number of digits is greater than the # locations in the picture, the digits will be changed to asterisks, displaying something like **,***.**.

    .

    Dynamic locale directive changes

    If you set Locale keys corresponding to some MiniVend catalog.cfg directives, those values will be set when setting the locale.

    PageDir
    To use a different page directory for different locales, set the PageDir key. To have two separate language page sets, French and English, you would set:

    # Establish the default at startup PageDir english Locale fr_FR PageDir francais Locale en_US PageDir english

    ImageDir
    To use a different image directory for different locales, set the ImageDir key. To have two separate language button sets, French and English, you would set:

    # Establish the default at startup ImageDir /images/english/ Locale fr_FR ImageDir /images/francais/ Locale en_US ImageDir /images/english/

    PriceField
    To use a different field in the products database for pricing based on locale, set the PriceField locale setting.

    # Establish the default at startup PriceField price Locale fr_FR PriceField prix

    The default will always be price, but if the locale fr_FR is set, the PriceField directive will change to prix to give prices in francs instead of dollars.

    If PriceBreaks is enabled, then the field prix from the pricing database will be used to develop the quantity pricing. NOTE: If no Locale settings are present, it will always be price, irrespective of the PriceField setting. Otherwise it will always match PriceField .

    PriceDivide
    Normally used to enable penny pricing with a setting of 100, this can be used to do an automatic conversion factor based on locale.

    # Default at startup is 1 if not set # Franc is strong these days! Locale fr_FR PriceDivide .20

    The price will now be divided by .20, yielding franc prices five times that of the dollar.

    PriceCommas
    Perhaps this isn't a good name anymore, but it controls whether the mon_thousands_sep will be used for standard currency formatting. Ignored if using price_picture . Set to 1 or 0, to enable and disable respectively. DO NOT USE Yes and No.

    # Default at startup is Yes if not set PriceCommas Yes Locale fr_FR PriceCommas 0 Locale en_US PriceCommas 1

    UseModifier
    Changes the fields from that set shopping cart options.

    # Default at startup is 1 if not set # Franc is strong these days! UseModifier format Locale fr_FR UseModifier formats

    If a previous setting was made for an item based on another locale, it will be maintained.

    PriceAdjustment
    Changes the fields from UseModifier that will be used to adjust pricing. used to do an automatic conversion factor based on locale.

    # Default at startup PriceAdjustment format Locale fr_FR PriceAdjustment formats

    TaxShipping,SalesTax
    Same as the standard directives.

    DescriptionField
    This changes the field accessed by default with the [item-description] and [description code] tags.

    # Establish the default at startup DescriptionField description Locale fr_FR DescriptionField desc_fr

    The [locale] tag
    You can set standard error messages based on Locale settings. Make sure you don't use any of the predefined keys -- it will be safe if you begin the key with msg_ or such. The default message is set between the [locale key] and [/locale] tags. See the example above.

    .

    Sorting based on Locale

    The MiniVend [sort database:field] keys will use the LC_COLLATE setting for a locale provided that:

    • Your operating system and C compiler have such support for POSIX, and you have the locale definitions set.

    • You have Perl 5.004.

    • The locale setting matches one of your configured locales.

    It is beyond the scope of this document to discuss these issues,.and you should contact your system administrator or local wizard to help you set up locales on your system. NOTE: Windows locales are not supported for sorting.

    If you had this arbitrary database named letters:

    code letter 00-0011 f 99-102 é 19-202 a

    and this loop:

    [loop 19-202 00-0011 99-102] [sort letters:letter] [loop-data letters letter] [loop-code] [/loop]

    Using the default C setting for LC_COLLATE it would display:

    a 19-202 f 00-0011 é 99-102

    If the proper LC_COLLATE settings for locale fr_FR were in effect, then it would become:

    a 19-202 é 99-102 f 00-0011


    MINIVEND CONFIGURATION FILES

    MiniVend can and usually does run multiple catalogs on the same server. If no Catalog directives are present in the main minivend.cfg file, the server will read only a single catalog's information from the one minivend.cfg file, just as in early versions of the program.

    You normally call configuration directives with the directive as the first word on the line, with it's value or values following. Leading whitespace is stripped from the value.

    You may call additional files with a rudimentary #include file statement. The directives called with includes are always appended at the end of the main configuration file. Though order is rarely important in the configuration files, you must define any directory settings in the main configuration file near the top if they are to be used to base the file calls of subsequent directives. Files are relative to the catalog directory (or MiniVend software directory, if in the main minivend.cfg file).

    You can also use a type of ``here document'' to specify MiniVend directives, with the usual <<MARKER syntax. No semicolon is used to terminate the marker.

    Server Configuration File

    The VendRoot directory, specified in the main program minivend, is the default location of all of the MiniVend program, configuration, special, and library files. Unless changed in minivend, the main MiniVend server configuration file will be minivend.cfg in the VendRoot directory.

    If no Catalog directives are present, all of the directives listed under Catalog Configuration File are operative for the single catalog that will be served by MiniVend.

    Otherwise, there are only a few directives that are defined in the minivend.cfg file.

    AdminSub
    Specifies subroutine names that may not be run unless the user is the administrative user for the catalog. (See MasterHost , Password , and RemoteUser ).

    AdminSub export_database

    AllowGlobal
    Specifies catalog identifiers that may define subroutines and UserTag entries that can operate with the full permissions of the server. DON'T USE THIS UNLESS YOU TRUST THE CATALOG USER IMPLICITLY. Default is blank.

    AllowGlobal simple

    Catalog
    Specifies a catalog that can run using this MiniVend server. There are three required parameters, separated by spaces and/or tabs.

    The first is the name of the catalog -- it will be referred to as that name in error, warning, and informational messages. It must contain only alphanumeric characters, hyphens, and underscores.

    The second is the base directory of the catalog. If the directory does not contain a catalog.cfg file, the server will report an error and refuse to start.

    The third directive is very important to get right -- it is the SCRIPT_NAME of the vlink program that runs the catalog. It must be unique from other CGI program paths that run on this server -- that is how the catalog is selected for operation.

    Catalog simple /home/minivend/simple /cgi-bin/simple

    As of MiniVend 3.0, you can specify any number of alias script names as additional parameters. This allows the calling path to be different while still calling the same catalog -- it is most probably useful when calling an SSL server or a members-only executable that requires a username/password via HTTP Basic authorization. All branched links will be called using the aliased URL.

    In addition, if you set the global directive FullUrl to yes, you can (and must in all catalogs) specify the server name that will call the catalog. This allows you to have many virtual domains, all of which use /cgi-bin/shop as the calling URL.

    DisplayErrors
    While all errors are reported in the error log file, you can also have errors displayed by the browser. This is convenient while you are testing your configuration. Unless this is set, the DisplayErrors setting in the user catalogs will have no effect. Default is No.

    DisplayErrors Yes

    DomainTail
    Implements the domain/IP session qualifiers so that only the major domain is used to qualify the session ID. This is a compromise on security, but it allows non-cookie-accepting browsers like AOL's V2.0 to use multiple proxy servers. Default is yes, since most everyone wants AOL to work. DomainTail No

    Environment
    Environment variables to inherit from the calling CGI link program. And example might be PGPPATH, used to set the directory which PGP will use to find its key ring.

    Environment MSQL_HOME MSQL_TCP_PORT MSQL_UNIX_PORT

    FullUrl
    Normally MiniVend determines which catalog to call by determining the SCRIPT_NAME from the CGI call. This means that different (and maybe virtual) hosts cannot use the same SCRIPT_NAME to call different catalogs. Set FullUrl to Yes to differentiate based on the calling host. You must then set the server name in the Catalog directive accordingly, i.e. yourdomain.com/cgi-bin/simple. A yes/no directive, the default is No.

    FullUrl Yes

    GlobalSub
    Defines a global subroutine for use by the [perl sub] subname arg [/perl] construct. Use the ``here document'' capability of MiniVend configuration files to make it easy to define:

        GlobalSub <<EOF
        sub count_orders {
            my $counter = new File::CounterFile "/tmp/count_orders", '1';
            my $number = $counter->inc();
            return "There have been $number orders placed.\n";
        }
        EOF
    
    

    As with Perl ``here documents'', the EOF (or other end marker) must be the ONLY thing on the line, with no leading or trailing white space. Do not append a semicolon to the marker. (The above appears indented -- it should not be that way in the file!)

    IMPORTANT NOTE: These global subroutines are not subject to security checks -- they can do most anything! For most purposes, scratch subroutines or catalog subroutines (also Sub ) are better.

    GlobalSub routines are subject to full Perl use strict checking, so you will get errors if you do not use lexical variables or complete package qualifications for your variables.

    HammerLock
    The number of seconds after which a locked session could be considered to be lost due to malfunction. This will kill the lock on the session. Only here for monitoring of session hand-off, if this error shows up in the error log the system setup should be examined. Default is 30.

    HammerLock 60

    HouseKeeping
    How often, in seconds, the MiniVend server will ``wake up'' and look for user reconfiguration requests and hung search processes. On some systems, this wakeup is the only time the server will terminate in response to a stop command. Default is 60.

    HouseKeeping 10

    IpHead
    Implements the domain/IP session qualifiers so that only the first two dot-quads of the IP address are used to qualify the session ID. This is a compromise on security, but it allows non-cookie-accepting browsers like AOL's V2.0 to use multiple proxy servers.

    DomainTail is preferable unless one of your HTTP servers does not do host name lookups.

    Default is No, and DomainTail must be set to No for it to operate.

    IpHead Yes

    LockoutCommand
    The name of a command (as you would enter it from the shell) that will lock out the host IP of an offending system. The IP address will be substituted for the first occurrence of the string %s.

    This will be executed with the user ID that MiniVend runs under, so any commands that require root access will have to be wrapped with an SUID program.

    On Linux, you might lock out a host with:

    ipfwadm -I -i deny -S %s

    This would require root permissions, however, under normal circumstances. You can use sudo or another method to wrap and allow the command.

    You can write a script which modifies an appropriate access control file, such as .htaccess for your CGI directory, to do another level of lockout. A simple command line containing perl -0777 -npi -e 's/deny/deny from %s\ndeny/' /home/me/cgi-bin/.htaccess would work as well (remember, the %s will become the IP address of the offending user).

    LockoutCommand lockout %s

    MaxServers
    The maximum number of servers that will be spawned to handle page requests. If more than MaxServers requests are pending, they will be queued (within the defined capability of the operating system, usually 5 pending requests) until the number of active servers goes below that value.

    MaxServers 4

    MultiServer
    If defined to be true, then multiple servers can share the socket and serve users. Not usable on SGI systems. Default is no

    MultiServer yes

    NoAbsolute
    Whether MiniVend [file ...] and other tags can read any file on the system (that is readable by the user id running the MiniVend daemon). The default is No, which allows any file to be read -- this should be changed in a multi-user environment to minimize security problems.

    NoAbsolute Yes

    SafeSignals
    If your operating system does not have a re-entrant C library that can guarantee that signal race conditions will not occur, then set this to NO.

    BSDI and FreeBSD libraries are NOT safe, and SafeSignals will automatically be disabled for those operating systems.

    In general, if MiniVend ever just ``hangs'', particularly if you can see a perl.core file, disable this directive.

    SafeSignals No

    SafeUntrap
    Sets the codes that will be untrapped in the Safe.pm module, used for embedded Perl and conditional operations. You can see the Safe.pm documentation by typing perldoc Safe at the command prompt. The default is 249 148 for Perl 5.003, and ftfile sort for Perl 5.003_20 and above, which untraps the file existence test operator and the sort operator. Define it as blank to not allow any besides the default restrictive operators.

    SafeUntrap ftfile sort ftewrite

    SendMailProgram
    Specifies the program used to send email. Defaults to '/usr/lib/sendmail'. If it is not found at startup, MiniVend will complain and refuse to start.

    SendMailProgram /bin/mailer

    SubCatalog
    Allows definition of a catalog which shares most of the characteristics of another catalog. Only the items that are changed from the base catalog are added. The parameters are 1) the catalog ID 2) the base catalog ID, 3) the directory to use (typically the same as the base catalog), and 4) the SCRIPT_NAME that will trigger the catalog. Any additional parameters are aliases for the SCRIPT_NAME.

    The main reason that this would be used would be to conserve memory in a series of stores that share most of the same pages or databases.

    SubCatalog sample2 sample /usr/catalogs/sample /cgi-bin/sample2

    TcpHost
    When running in INET mode, using tlink, specifies the hosts that are allowed to send/receive transactions from any catalog on this MiniVend server. Can be either an name or IP number, and multiple hosts can be specified in a space-separated list. Default is localhost.

    TcpHost localhost secure.domain.com

    TcpPort
    When running in INET mode, using tlink, specifies the port that will be monitored by the MiniVend server. Default is 7786.

    TcpPort 7786

    TolerateGet
    Sometimes proxy servers screw up and cache POST forms. This is mainly a problem from forms that are identical, such as popular items being placed in the basket and then the user pushing the checkout button.

    Set TolerateGet to Yes to allow GET forms. You will be able to use METHOD=GET on the form if necessary, subject to the normal limits of query string length. You will want to set the variable mv_session_id to ensure that the session is not lost on browsers that don't support cookies:

    <INPUT TYPE=hidden NAME=mv_session_id VALUE="[data session id]">

    It would be typical to employ this on your shopping cart page or perhaps put it on the interact page that is shown when the normal error is received.

    TolerateGet Yes

    UserBuild
    A Yes/No directive. Determines whether users are allowed to trigger static builds of their MiniVend catalogs. Default is no, as you do not typically want to allow rebuilds from the running server.

    Variable
    Defines a global variable that will be available in all catalogs with the notation @@Variable@@. Variable identifiers must begin with a capital letter, and can contain only word characters (A-Z,a-z,0-9 and underscore) -- they are case-sensitive. If using the ParseVariables directive, only variables in ALL CAPS will be parsed. These are substituted first in any MiniVend page, and can contain any valid MiniVend tags including catalog variables.

    Variable DOCUMENT_ROOT /usr/local/etc/httpd/htdocs

    .

    Catalog Configuration File

    If multiple catalogs are to be run, each must have a catalog.cfg file located in the catalog base directory. It contains most of the configurable parameters for MiniVend -- each is independent from catalog to catalog.

    Required Configuration Directives

    In the catalog configuration file, these directives are required :

    VendURL
    Specifies the base URL that will run vlink as a cgi-bin program.

    VendURL http://machine.company.com/cgi-bin/vlink

    MailOrderTo
    Specifies the email address to mail completed orders to.

    MailOrderTo orders@xyzcorp.com

    .

    Optional Configuration Directives

    These directives all have default values and are optional.

    ActionMap
    Allows setting of button actions for particular names. The predefined names are:

    cancel Cancel order and wipe credit card numbers control Control help, colors, etc. checkout Call checkout form refresh Refresh order page (update quantities, etc.) return Go to previous page (or page defined in mv_nextpage variable) search Search for an item in the catalog set Update a database submit Submit order or form

    Actions are overwritten, even the default ones, if re-defined. Default is blank. Can be set as many times as necessary. Not case sensitive.

    ActionMap refresh change ActionMap refresh validate ActionMap cancel erase ActionMap submit next ActionMap control color

    AdminDatabase
    When set to one or more MiniVend database identifiers, any pages using data items from the specified database(s) will not be allowed for display unless the user the catalog operator -- i.e. is authenticated by one of Password , MasterHost , or RemoteUser . The special page violation will be displayed if another user attempts to access a page containing elements from the database(s).

    AdminDatabase inventory

    AdminPage
    When set to one or more MiniVend page names, pages with that name will not be allowed for display unless the user the catalog operator -- i.e. is authenticated by one of Password , MasterHost , or RemoteUser . The special page violation will be displayed if another user attempts to access the page(s).

    AdminPage config/menu

    AlwaysSecure
    Determines whether checkout page operations should always be secure. Set it to the pages that should always be secure, separated by spaces and/or tabs.

    AlwaysSecure checkout

    AsciiBackend
    A file name to log order fields in (set by BackendOrder). Unless preceded by a leading '/', will be placed relative to VendRoot. If the first character is a '|', it is the name of a program to send the fields to. Disabled by default.

    AsciiBackend |/usr/order/scripts/place_order

    AsciiTrack
    A file name to log formatted orders in. Unless preceded by a leading '/', will be placed relative to the catalog directory. Disabled by default.

    AsciiTrack etc/orders.txt

    BackendOrder
    Controls the fields that are prepended to the item codes and quantities for the backend ordering capability. These are the values from the user checkout forms. You can access any value in that hash. If blank, no backend ordering is in force. Default is blank.

    BackendOrder name,address,city,state,zip,mv_shipmode

    ButtonBars
    The ButtonBars directive allows you to define several preset button bars that reside in files. The button bar file will usually contain an IMG link, along with its associated client-side image map. This allows you to insert a [buttonbar 1] or [buttonbar 2] directive instead of the equivalent HTML, and is designed to make it easy to change the look of your pages with the change of one file. If the file does not exist at program configuration time, the tag is simply stripped. The line in the catalog.cfg file takes the form of the directive, followed by any number of vend-style file names (relative to the PageDir, with no .html suffix).

    ButtonBars bars/button0 bars/button1 bars/button2 bars/button3

    The ButtonBars directive is deprecated in favor of Variable and UserTag.

    CheckoutFrame
    The frame name where the checkout page will go, if frames are enabled. Default is not set, or making it subject to the default target.

    CheckoutFrame _blank

    CheckoutPage
    The name of the default page to send the user to when the [finish-order] tag is used. Default is ``order''. This is overridden in any number of ways from order forms.

    CheckoutPage basket

    ClearCache
    A yes/no directive. When set to yes, each time the catalog is reconfigured or the MiniVend server is restarted the page and search caches will be cleared. Default is No. The cache can always be cleared by removing all files in the ScratchDir /PageCache and ScratchDir /SearchCache directories. In addition, if static page building is being used, the output directory will be cleared before build if this directive is set.

    ClearCache Yes

    CollectData
    The points at which to log various data items collected by MiniVend, such as failed or successful searches. This allows you to find out what your customers are searching for and NOT finding -- perhaps you want to add it, or change your product description to match. Uses something like the HTTP common log format.

    The choices to enter are:

    matched Search strings that match nomatch Search strings that fail to match page Pages that are accessed nopage Pages that are not found basket Items placed in shopping carts cache Pages/searches added to cache

    Enter as a space or comma-separated list, i.e.

    CollectData matched,nomatch,page

    Orders are typically logged to other files via AsciiTrack, AsciiBackend, or the [tag log ...]data[/tag] construct.

    CommonAdjust
    A MiniVend database identifier specifying a database that contains, keyed on the item attribute value (not the product code!), any price adjustments that are to be done based on item attributes.

    Care needs to be used. Each attribute specified in PriceAdjustment must have a corresponding column with the same name (case-sensitive), which when keyed by the item attribute value yields the price adjustment (if any) to be made for any item having that attribute and containing that value. Used in concert with PriceAdjustment , and is not set by default, disabling the common adjustment database feature.

    CommonAdjust adjustments

    Can be set in the Locale settings to allow different price adjustment databases for different currencies (MV3.07 and up).

    ConfigDir
    The default directory where directive values will be read from when using the <file notation. Default is config . The name is relative to the catalog directory unless preceded by a /.

    ConfigDir variables

    CookieDomain
    Allows you to set a domain so that two servers can handle traffic. For example, if you wanted to use server addresses of secure.yourdomain.com and www.yourdomain.com then you could set it to:

    CookieDomain .yourdomain.com

    It must have at least two periods or browsers will ignore it.

    Cookies
    Determines whether we will send (and read back) a cookie to get the session ID for links that go outside the catalog. Allows arbitrary HREF links to be placed in MiniVend pages, while still saving the contents of the session. The default is Yes, which is a change from MiniVend 2.x.

    Cookies Yes

    If the Cookies directive is enabled, and mv_save_session is set upon submission of a user form (or in the CGI variables through a perl GlobalSub ), the cookie will be persistent for the period defined by SaveExpire .

    Caching and static page building will never be in effect unless this directive is enabled.

    CreditCardAuto
    If set to Yes, enables the encryption and saving of credit card information. In order for this to work properly, the EncryptProgram directive must be set to properly encode the field. The best way to set EncryptProgram is with PGP in the ASCII armor mode (the option set '-feat' is used).

    This option uses the following standard fields on MiniVend order processing forms:

    mv_credit_card_number The actual credit card number, which will be wiped from memory if it verifies as a valid Amex, Visa, MC, or Discover card number. mv_credit_card_exp_all The expiration date, as a text field in the form MM/YY (will take a four-digit year as well). If it is not present, the fields mv_credit_card_exp_month and mv_credit_card_exp_year are looked at. It is set by MiniVend when the card validation returns, if not previously set. mv_credit_card_exp_month The expiration date month, used if the mv_credit_card_exp_all field is not present. It is set by MiniVend when the card validation returns, if not previously set. mv_credit_card_exp_year The expiration date year, used if the mv_credit_card_exp_all field is not present. It is set by MiniVend when the card validation returns, if not previously set. mv_credit_card_error Set by MiniVend to indicate the error if the card does not validate properly. The error message is not too enlightening if validation is the problem. mv_credit_card_force Set this value to 1 to force MiniVend to encrypt the card despite its idea of validity. Will still set the flag for validity to 0 if the number/date does not validate. Still won't accept badly formatted expiration dates. mv_credit_card_info Set by MiniVend to the encrypted card information if the card validates properly. If PGP is used in ASCII armor mode, this field can be placed on the order report and embedded in the order email, replete with markers. This allows a secure order to be read for content, without exposing the credit card number to risk. mv_credit_card_valid Set by Minivend to true, or 1, if the the card validates properly. Set to 0 otherwise.

    PGP is recommended as the encryption program, though you should remember that US commercial organizations may require a license for RSA.

    CreditCardAuto Yes

    CustomShipping
    If not blank, enables the addition of shipping charges based on quantity or weight of items ordered. See SHIPPING .

    CustomShipping quantity

    CyberCash
    A yes/no directive, default no. Enables CyberCash payment protocols -- see Using CyberCash .

    CyberCash Yes

    DataDir
    The location of the extra database files if no path information is provided. Set to ``products'' as the default, and is relative to VendRoot if there is no leading slash. May not be set to an absolute directory unless NoAbsolute is defined as No.

    DataDir /user/data

    Database
    Definition of an arbitrary database, in the form "Database database file type``, where ''file" is the name of an ASCII file in the same format as the products database. The file is relative to VendRoot, and is put in DataDir if no path is provided. Records can be accessed with the [data database field key] tag. Database names are restricted to the alphanumeric characters (including the underscore). See DATABASES .

    Database BookReviews reviews.txt 3

    DefaultShipping
    This sets the default shipping mode by initializing the variable mv_ship_mode. If not set in catalog.cfg , it is default.

    DefaultShipping UPS

    Delimiter
    One of TAB, PIPE, CSV, or your own custom delimiter. (It is not suggested that you use a custom delimiter). TAB means a tab-delimited database (the default if not set), PIPE a pipe-delimited one, and CSV a quote-comma format.

    Delimiter CSV

    DescriptionField
    The field that will be accessed with the [item-description] element.

    DescriptionField ProductDescription

    Default is description . It is no longer a fatal error if this field does not exist.

    DisplayErrors
    If the administrator has enabled DisplayErrors globally, then setting this to ``Yes'' will display the error returned from MiniVend in case something is wrong with embedded Perl programs, tags, or (horrors!) MiniVend itself. Usually you will only want to use this during development or debugging -- default is no.

    DisplayErrors Yes

    DynamicData
    When set to one or more MiniVend database identifiers, any pages using data items from the specified database(s) will not be cached or built statically. This allows dynamic updating of certain arbitrary (or even product) databases while still allowing static/cached page performance gains on pages not using those data items.

    DynamicData inventory

    Overridden by [tag flag build][/tag] or [tag flag cache][/tag], depending on context.

    EncryptProgram
    Contains a program command line specification that indicates how an external encryption program will work. Two placeholders, %p and %f, are defined, which are replaced at encryption time with the password and temporary file name respectively. See Order Security .

    This is separate from the PGP directive, which enables PGP encryption of the entire order.

    If PGP is the encryption program (MiniVend determines this by searching for the string pgp in the command string), no password field or file field need be used -- the field mv_credit_card_number will never be written to disk in that case.

    EncryptProgram /usr/local/bin/pgp -feat sales@company.com

    ErrorFile
    This is where MiniVend will write its runtime errors for THIS CATALOG ONLY. It can be shared with other catalogs or the main MiniVend error log, but if you make it root-based, be careful that you have permission to write the file, or bad things will happen.

    ErrorFile /home/minivend/error.log

    ExtraSecure
    Disallows access to pages which are marked with AlwaysSecure unless the browser is in HTTPS mode. A yes/no directive -- default is 'No'.

    ExtraSecure Yes

    FieldDelimiter
    In conjunction with RecordDelimiter , allows custom database formats to be defined. The first string is the database type identifier, and the second is the field delimiter with C/Perl style double-quoted string format, i.e. \n is a newline.

    FieldDelimiter Tilde ~ RecordDelimiter Tilde \n Database mydata mydata.txt Tilde

    FinishOrder
    A text string or image tag which is substituted for the [finish_order] tag.

    FinishOrder <IMG SRC="/icons/fin_ord.gif" ALT="Check Basket">

    This is deprecated, and may be removed from future versions of MiniVend.

    FormIgnore
    Set to the name(s) of variables that should not be carried in the user session values. Must match exactly and are case sensitive.

    FormIgnore mv_searchtype

    FractionalItems
    Whether items in the shopping cart should be allowed to be fractional, i.e. 2.5 or 1.25. Default is no.

    FractionalItems Yes

    FrameFlyPage
    The MiniVend-style page name (i.e. no .html extension, relative to PageDir ) which contains the special on-the-fly page for when frames are in use. If not set (the default), the standard flypage will be used.

    FrameFlyPage fr_flypage

    FrameLinkDir
    The relative directory where on-the-fly pages will be sent during static page builds -- it is relative to StaticDir . Default is 'framefly'.

    FrameLinkDir fr_fly

    FrameOrderPage
    The MiniVend-style page name (i.e. no .html extension, relative to PageDir ) which contains the special order page for when frames are in use. If not set (the default), the standard order page will be used. Vaguely deprecated, as multiple order pages are better set with the mv_orderpage variable.

    FrameOrderPage fr_order

    FrameSearchPage
    The MiniVend-style page name (i.e. no .html extension, relative to PageDir ) which contains the special search page for when frames are in use. If not set (the default), the standard search page will be used. Vaguely deprecated, as multiple search pages are better set with the mv_search_page variable.

    FrameSearchPage fr_resul

    FramesDefault
    Whether the first access by a user will place them in frames mode. Default is no.

    FramesDefault Yes

    Glimpse
    The pathname for the glimpse command, used if glimpse searches are to be enabled. If you wish to use glimpseserver, you must include the -C, -J, and -K tags if they are needed.

    Glimpse /usr/local/bin/glimpse -C -J srch_engine -K2345

    Help
    The Help directive allows you to define an unlimited number of help messages or image specifications that reside in a file (or files). It is called by the [help item] tag, where item is the first line of a help file entry which looks like:

    help1 This is help item one. It ends after a blank line, and is called by a [help help1] element embedded in a MiniVend page. help2 This is help item two. It ends after a blank line, and is called by a [help help2] element embedded in a MiniVend page.

    If the file (or the entry) does not exist at program configuration time, the tag is simply stripped. The line in the catalog.cfg file takes the form of the directive, followed by any number of vend-style file names (relative to the PageDir, with no .html suffix). See the demo for an example of how it is used.

    Help help/hintfile

    The Help directive is vaguely deprecated in favor of arbitrary databases and Variable .

    ImageAlias
    Aliases for images, ala Apache/NCSA ScriptAlias and Alias directives. Relocates images based in a particular directory to another for MiniVend use -- operates after ImageDir. Useful for editing MiniVend pages with an HTML editor. Default is blank.

    ImageAlias /images/ /thiscatalog/images/

    ImageDir
    The directory where all relative IMG and INPUT source file specifications are based. IT MUST HAVE A TRAILING / TO WORK. If the images are to be in the DocumentRoot (of the HTTP server or virtual server) subdirectory images, for example, you would use the ImageDir specification '/images/'. This would change SRC=``order.gif'' to SRC=``/images/order.gif'' in IMG and INPUT tags. It has no effect on other SRC tags.

    ImageDir /images/

    Can be set in the Locale settings to allow different image sets for different locales (MV3.07 and up).

    ItemLinkDir
    The directory where the [item_link] tag will base all of its hot links in, relative to the pages directory. The default is blank, basing all links in the pages directory. If set, it needs a trailing '/' to operate properly. This directive is deprecated, and may disappear in future versions of MiniVend.

    ItemLinkDir partno/

    ItemLinkValue
    Specifies the text or image you want to use to provide a clickable link to the catalog page when using the [item_link] tag (in the search form, or other forms). This directive is deprecated, and may disappear in future versions of MiniVend.

    ItemLinkValue <IMG SRC="/images/gopage.gif" ALT="GO TO PAGE">

    Locale
    Sets the special locale array. Tries to use POSIX setlocale based on the value of itself, then tries to accept a custom setting with the proper definitions of mon_decimal_point, thousands_sep, and frac_digits, which are the the only international settings required. Default if not set is to use US-English settings.

    Example of the custom setting:

    Locale custom mon_decimal_point , mon_thousands_sep . frac_digits 0

    Example of POSIX setlocale for France, if properly aliased:

    Locale fr

    See setlocale(3) for more information. If embedded Perl code is used to sort search returns, then the setlocale() will carry through to string collation.

    MiniVend 3.07 extends the Locale array to accept many more settings. See Internationalization.

    LogFile
    A file where user pages accesses and search specifications will be logged if CollectData is set. Defaults to etc/log .

    LogFile etc/log

    MasterHost
    The IP address that can reconfigure the catalog. Default is blank, disabling remote check of IP address.

    MasterHost 10.10.10.1

    MixMatch
    A yes/no directive. A setting of yes says that quantity price breaks will be on TOTAL quantity, no says that quantity price breaks are on a per-item quantity. Default is no.

    MixMatch yes

    MsqlDB
    Sets the name of the mSQL database (must be present on the default server). Defaults to minivend.

    MsqlDB catalog

    Mv_AlinkColor
    Sets the accessed link colors to be used in the color schemes. The line must begin with 'BEGIN', then is followed by up to 15 RGB color specifications for visited link color. The specification can be in #RRGGBB color format, or can be one of the colors that will be recognized (steelblue, white, etc.) Each color should be separated by one or more spaces. Set to none to disable a color (use the browser default) for a particular scheme. Remember, the schemes are numbered in the order that they occur.

    Mv_VlinkColor BEGIN orange none blue

    Mv_Background
    Sets the background patterns to be used in the color schemes. The line must begin with 'BEGIN', then is followed by up to 15 pattern URLs containing background patterns to be used with the color schemes. Each pattern should be separated by one or more spaces. set to 0 to disable a background pattern for a particular scheme. Remember, the schemes are numbered in the order that they occur.

    Mv_Background BEGIN /images/blue_pap.gif 0 /images/temple.jpg

    Mv_BgColor
    Sets the background colors to be used in the color schemes. The line must begin with 'BEGIN', then is followed by up to 15 RGB color specifications for background color. The specification can be in #RRGGBB color format, or can be one of the colors that will be recognized (steelblue, white, etc.) Each color should be separated by one or more spaces. Set to none to disable a color (use the browser default) for a particular scheme. Remember, the schemes are numbered in the order that they occur.

    Mv_BgColor BEGIN steelblue none white

    Mv_LinkColor
    Sets the link colors to be used in the color schemes. The line must begin with 'BEGIN', then is followed by up to 15 RGB color specifications for link color. The specification can be in #RRGGBB color format, or can be one of the colors that will be recognized (steelblue, white, etc.) Each color should be separated by one or more spaces. Set to none to disable a color (use the browser default) for a particular scheme. Remember, the schemes are numbered in the order that they occur.

    Mv_LinkColor BEGIN ltgreen none red

    Mv_TextColor
    Sets the text colors to be used in the color schemes. The colors are accessed with the [body n] tag, where n is the color scheme number. The line must begin with 'BEGIN', then is followed by up to 15 RGB color specifications for text color. The specification can be in #RRGGBB color format, or can be one of the colors that will be recognized (steelblue, white, etc.) Each color should be separated by one or more spaces. Set to none to disable a color (use the browser default) for a particular scheme. Remember, the schemes are numbered in the order that they occur, beginning with 1.

    Mv_TextColor BEGIN white none black

    Mv_VlinkColor
    Sets the visited link colors to be used in the color schemes. The line must begin with 'BEGIN', then is followed by up to 15 RGB color specifications for visited link color. The specification can be in #RRGGBB color format, or can be one of the colors that will be recognized (steelblue, white, etc.) Each color should be separated by one or more spaces. Set to none to disable a color (use the browser default) for a particular scheme. Remember, the schemes are numbered in the order that they occur.

    Mv_VlinkColor BEGIN orange none blue

    NewEscape
    A yes/no directive. When set to Yes, it disallows the old-style period escaping of one-click search spec strings, and allows HTTP-style escaping of passed arguments (the [page name arg] tag, among others).

    This should probably be set to Yes for new catalogs.

    NewEscape Yes

    NewReport
    A yes/no directive. When set to No, it allows the old-style $variable interpolation on MiniVend order reports. Default is Yes, where $variable values are not interpolated with user session values (you use the [value variable] tag instead).

    The default prevents clashes with embedded Perl code.

    NewReport No

    NewTags
    A yes/no directive. When set to Yes, it defaults all pages to using the new page syntax. This can be counteracted with an [old] tag at the very top of the page, or by surrounding older sections of code with the [compat][/compat] tag pair. Default is No.

    NewTags No

    NoCache
    The names of MiniVend pages that are not to be cached (if Page Cache is being used) or built statically (if STATIC PAGE BUILDING is in use). If the name is a directory, then no pages in that directory (or any below it) be cached or built statically.

    NoCache ord NoCache special

    NoImport
    When set to one or more MiniVend database identifiers, those database(s) will never be subject to import. Useful for SQL databases, or databases that will *never* change.

    NoImport inventory

    NonTaxableField
    The name of the field in the products database that is set (to 1 or yes) if an item is not to be taxed. Will log an error and tax it anyway if the field doesn't exist in the database. Blank by default, disabling the feature.

    NonTaxableField wholesale

    OfflineDir
    The location of the offline database files for use with the MiniVend offline database build command. Set to ``offline'' as the default, and is relative to VendRoot if there is no leading slash.

    OfflineDir /usr/data/minivend/offline

    OldShipping
    Defines compatibility with older MiniVend shipping files -- they will break if using formulas where x is used as the substituted-for string for the accumulated total. A yes/no directive -- default is No. This will disappear soon.

    OldShipping Yes

    OrderCounter
    The name of the file (relative to catalog root if no leading /) that maintains the order number counter. If not set, the order will be assigned a string based on the time of the order and the user's session number.

    OrderCounter etc/order.number

    OrderFrame
    The frame name where the order page will go, if frames are enabled. If the frame doesn't exist, a new frame will be created. The default is '_top', which fills the browser window with the page.

    OrderFrame _blank

    OrderLineLimit
    The number of items that the user is allowed to place in the shopping cart. Some poorly-mannered robots may ``attack'' your site by following all links one after another. Some even ignore any robots.txt file you may have created. If one of these bad robots orders several dozen or more items, then the time required to save and restore the shopping cart from the user session may become excessive.

    If the limit is exceeded, then the command defined in the Global directive LockoutCommand will be executed and the shopping cart will be emptied. The default is 0, disabling the check. Set it to a number greater than the number of line items you ever expect a user to order.

    OrderLineLimit 50

    OrderProfile
    Allows an unlimited number of order profiles to be set up, specifying complex checks to be performed at each of the steps in the checkout process. The files specified can be located anywhere -- if relative paths are used, they are relative to the catalog root directory.

    OrderProfile prof/order0 prof/order1 prof/order2

    They are accessed by setting the mv_order_profile variable to the name of the order profile. Multiple profiles can reside in the same file, if separated by __END__ tokens, which must be on a line by themselves.

    The profile is named by placing a name following a __NAME__ pragma:

    __NAME__ billing

    The __NAME__ must begin the line, and be followed by whitespace and then the name. The search profile can then be accessed by mv_order_profile=``billing'' . See Advanced Multi-level Order Pages .

    OrderReport
    The location of the simple order report file. Defaults to etc/report . Not used frequently in later MiniVends, as the custom order report file is much more flexible.

    OrderReport /data/order-form

    PageCache
    When set to Yes, it will enable the caching of pages if the client browser has cookie capability. If the page has dynamic elements, it will not be cached. This can improve performance especially on large pages, since the page does not have to be parsed every time -- just the first. It does not make sense to enable this while enabling StaticFly -- however catalogs with large numbers of items may wish to enable this. A yes/no directive -- default is No.

    PageCache yes

    PageDir
    Location of catalog pages. Defaults to the pages subdirectory in the VendRoot directory.

    PageDir /data/catalog/pages

    Can be set in the Locale settings to allow different page sets for different locales (MV3.07 and up).

    PGP
    If credit card information is to be accepted, and the emailed order will go over an insecure network to reach its destination, PGP security should be used. The key ring to be used must be for the user that is running the MiniVend server, or defined by the environment variable PGPPATH, and the key user specified must have a key on the public key ring of that user.

    PGP /usr/local/bin/pgp -feat orders@company.com

    If this directive is non-null, the PGP command string as specified will be used to encrypt the entire order -- in addition to any encryption done as a result if CreditCardAuto , If for some reason an error comes from PGP, the customer will be given the special page failed .

    PageSelectField
    Sets a products database column which can be used to select the on-the-fly template page. This allows multiple on-the-fly pages to be defined. If the field is empty (no spaces, either!) then the default PageSelectField display_page

    ParseVariables
    Determines whether global and catalog variables will be parsed in the configuration file. Should be set to No until parsing is needed, turned on for the parsed directives, then set back to No. Default is No.

    Variable STORE_ID topshop ParseVariables Yes StaticDir /home/__STORE_ID__/www/cat ParseVariables No

    Password
    The encrypted password that, when entered and sent as RECONFIGURE_MINIVEND by the reconfigure program, will be checked against the user entry to enable reconfiguration.

    If you use MiniVend's htpasswd.pl (from 2.03 or higher) it will write the catalog configuration file if given catalog.cfg as the file name. The demo starts with an encrypted blank password, allowing you to just hit enter.

    Password bAWoVkuzphOX.

    PriceAdjustment
    A MiniVend item attribute (see UseModifier ) which contains a value upon which a price adjustment to the item may be made.

    A common case would be size. For shirts that are size XXL, you might wish to add a dollar to the price for an item. In that case, you can define a column in the standard pricing database pricing which is named ``XXL''. If a value is found in that column it will be added to the price for the item. Negative numbers result in subtraction if you wish to reduce the price based on an attribute.

    See CommonAdjust for another scheme that makes the same adjustment for any item having the attribute -- both schemes cannot be used at the same time. (This is true even if you were to change the value of $Vend::Cfg->{CommonAdjust} in a subroutine -- the pricing algorithm is built at catalog startup.)

    PriceAdjustment size

    Can be set in the Locale settings to allow different price adjustment fields for different currencies (MV3.07 and up).

    PriceBreaks
    The quantities where price breaks should be placed. Used to set up the pricing.asc entries to match actual pricing. Unlimited number of breaks -- only enter the lowest quantity it applies to.

    PriceBreaks 10 25 50 100 1000

    PriceCommas
    If you desire no commas in your price numbers (for the [item_price] tag) set this to no. The default is to use commas (or whatever is the thousands separator for your locale).

    PriceCommas no

    This would be overridden if a Locale price_picture is set.

    PriceDivide
    The number the price should be divided by to get the price in units (dollars or such). The default is one -- if you use penny pricing you can set it to 100.

    PriceDivide 100

    Can be set in the Locale settings to allow a price adjustment factor for different currencies (MV3.07 and up).

    PriceField
    The field in the product database that will be accessed with the [item-price] element. Default is ``price''.

    PriceField ProductPrice

    Can be set in the Locale settings to allow different price fields for different currencies (MV3.07 and up).

    ProductDir
    Location of the product files. Defaults to the products subdirectory of the VendRoot directory. May not be set to an absolute directory unless NoAbsolute is defined as No.

    ProductDir /data/catalog/for-sale

    Random
    The Random directive allows you to define an unlimited number of random messages or image specifications that reside in files. It is called by the [random] tag. You don't know which one will show up! Even I don't, it is random. If the file does not exist at program configuration time, the tag is simply stripped. The line in the minivend.cfg file takes the form of the directive, followed by any number of vend-style file names (relative to the PageDir, with no .html suffix).

    Random rand/message1 rand/message2 rand/message3 rand/message4

    ReadPermission and WritePermission
    By default, only the user account that MiniVend runs under (as set by the setuid permission on vlink) can read and write files created by MiniVend. WritePermission and ReadPermission can be set to user, group, or 'world'.

    ReadPermission group WritePermission group

    ReceiptPage
    The page to be displayed as a receipt after the user has submitted an order. Replaces the standard confirmation page. Blank by default, showing no receipt page to the user. Overridden by the value of mv_order_receipt.

    ReceiptPage receipt

    RecordDelimiter
    In conjunction with FieldDelimiter , allows custom database formats to be defined. The first string is the database type identifier, and the second is the record delimiter with C/Perl style double-quoted string format, i.e. \n is a newline.

    FieldDelimiter Tilde ~ RecordDelimiter Tilde \n Database mydata mydata.txt Tilde

    RemoteUser
    The value of the HTTP environment variable REMOTE_USER that will enable catalog reconfiguration. You need to enable HTTP basic authentication for this to work. Default is blank, disabling this check.

    RemoteUser Billyboy

    ReportIgnore
    A comma-separated list of items you don't want to have sent by email on the default order report. Default is blank, or none. Fields beginning with 'mv_', the MiniVend special variables, are automatically ignored. No additional fields will be used if you are relying on the newer HTML-style order report.

    ReportIgnore credit_card_no

    RequiredFields
    A comma-separated list of items you want to make sure the customer fills in before an order can be submitted. If an empty field is found when the customer submits the order, the special page needfield.html will be displayed to request that they enter the information. No default. If custom order profiles are used, this is only done upon the final placement of the order.

    RequiredFields name,company,email,address,city,state,zip

    RobotLimit
    The RobotLimit directive defines the number of consecutive pages a user session may access without a 30 second pause. If the limit is exceeded, then the command defined in the Global directive LockoutCommand will be executed. The default is 0, disabling the check.

    RobotLimit 200

    Rotate
    The Rotate directive allows you to define an unlimited number of rotating messages or image specifications that reside in files. It is called by the [rotate] tag. If the file does not exist at program configuration time, the tag is simply stripped. The line in the catalog.cfg file takes the form of the directive, followed by any number of vend-style file names (relative to the PageDir, with no .html suffix).

    Rotate rotate/banner1 rotate/banner2 rotate/banner3 rotate/banner4

    SalesTax
    If non-blank, enables automatic addition of sales tax based on the order form. The value is a comma-separated list of the field names (as placed in order.html), in priority order, which should be used to look up sales tax percentage in the salestax.asc database. This database is not supplied with MiniVend -- it is typically received from a third party by quarterly or monthly subscription.

    SalesTax zip,state

    SaveExpire
    The length of time that saved sessions will persist before being expired. See SessionExpire for the format. Default is 30 days.

    SaveExpire 8 weeks

    ScratchDir
    The directory where scratch files will be written, notably cached searches. Defaults to VendRoot/etc.

    ScratchDir /tmp

    SearchCache
    Whether searches will be cached. Caching is disabled for browsers that don't allow cookies to be set. A yes/no directive -- default is No. The cached pages are stored in the directory ScratchDir /SearchCache.

    SearchCache Yes

    SearchFrame
    The frame name where search results will go, if frames are enabled. If the frame doesn't exist, a new frame will be created. The default is '_self'.

    SearchFrame main

    SearchProfile
    Allows an unlimited number of search profiles to be set up, specifying complex searches based on a single click. The directive accepts a file name, based in the catalog directory if the path is relative:

    SearchProfile etc/search.profiles

    As an added measure of control, the specification is evaluated with the special MiniVend tag syntax to provide conditional setting of search parameters.

    The following file specifies a dictionary-based search in the file 'dict.product':

    __NAME__ dict_search mv_search_file=dict.product mv_return_fields=1 [if value fast_search] mv_dict_limit=-1 mv_last=1 [/if] __END__

    The __NAME__ is the value you will specify in the mv_profile variable on the search form, as in

    <INPUT TYPE=hidden NAME=mv_profile VALUE="dict_search">

    or with mp=profile in the one-click search.

    [page scan/se=Renaissance/mp=dict_search]Renaissance Art[/page]

    Multiple profiles can reside in the same file, if separated by __END__ tokens. __NAME__ tokens should be left-aligned, and __END__ must be on a line by itself with no leading or trailing whitespace.

    SecureURL
    The base URL for secure forms/page transmissions. Normally it is the same as VendURL except for the https: protocol definition. Default is blank, disabling secure access.

    SecureURL https://machine.com/xyzcorp/cgi-bin/vlink

    SendMailProgram
    The location of the sendmail binary, needed for mailing orders. Must be found at startup. This often needs to be set for FreeBSD or BSDI.

    SendMailProgram /usr/sbin/sendmail

    SeparateItems
    Changes the default when ordering an item via MiniVend to allowing multiple lines on the order form for each item. The default, No, puts all orders with the same part number on the same line.

    Setting SeparateItems to Yes allows the item attributes to be easily set for different instances of the same part number, allowing easy setting of things such as size or color.

    SeparateItems Yes

    Can be overridden with the mv_separate_items variables (both scratch and user).

    SessionDatabase
    When storing sessions in a DBM database, specify the base name of the DBM file to use. The file extensions of .pag, .dir, .db, or .gdbm (depending on the DBM implementation used) will be appended.

    SessionDatabase session-data

    It is possible for multiple catalogs to share the same session file. This allows a ``mall'' to be set up where many store fronts use a common ordering point. It would be wise to share the order pages, salestax database, and shipping database if that is the case. You will also need to set SessionLockFile appropriately if the database is to be shared. Defaults to session , which is appropriate for separate session files (and therefore standalone catalogs). Can be an absolute path name if desired.

    SessionExpire
    A customer can exit their browser or leave the catalog pages at any time, and no indication is given to the HTTPD server aside from the lack of further requests that have the same session id. Old session information needs to be periodically expired. The SessionExpire specifies the minimum time to keep track of session information. Defaults to one day. Format is an integer number, followed by s(econds), m(inutes), h(ours), d(ays), or w(eeks).

    SessionExpire 4 hours

    SessionLockFile
    The file to use for locking coordination of the sessions.

    SessionLockFile session-data.lock

    It is possible for multiple catalogs to share the same session file. You will also need to set SessionDatabase appropriately if the database is to be shared. Defaults to session.lock , which is appropriate for separate session files (and therefore standalone catalogs). Can be an absolute path name if desired.

    Shipping
    Specifies a shipping charge to add onto the total price for items ordered. If you do not want to include a fixed shipping charge on the order page, leave this 0 and do not include the [shipping] element in the order page. Defaults to 0. Overridden by the CustomShipping directive.

    Shipping 5.00

    SpecialPage
    Sets a special page to other than its default value. Can be set as many times as necessary -- will have no effect if not one of the MiniVend Required Pages .

    SpecialPage checkout ord/checkout SpecialPage failed special/error_on_order SpecialPage interact special/browser_problem SpecialPage noproduct special/no_product_found SpecialPage order ord/basket SpecialPage search srch/results

    Static
    A yes/no directive. Enables static page building and display features. Default is no.

    Static Yes

    StaticAll
    A yes/no directive. Tells MiniVend to try and build all pages in the catalog statically when called with the static page build option. This is subject to the settings of StaticFly , StaticPath , and NoCache . Default is No. (Of course pages that have dynamic elements will not be built statically, though that may be overridden with [tag flag build][/tag] on the page in question.)

    StaticAll Yes

    StaticDepth
    The number of levels of static search building that will be done if a search results page contains a search. Default is one -- beware that it could be very long if you set it higher. Set to 0 to disable re-scanning of search results pages.

    StaticDepth 2

    StaticDir
    The absolute path of the directory which should be used as the root for static pages. The user ID executing MiniVend must have write permission on the directory (and all files within) if this is to work.

    StaticDir /home/you/www/catalog

    StaticFly
    A yes/no directive. If set to Yes, static builds will attempt to generate a page for every part number in the database using the on-the-fly page build capability. If pages are already present with those names, they will be overwritten. The default is No.

    StaticFly Yes

    StaticPage
    Tells MiniVend to build the named page (or pages, whitespace separated) when employing the static page-building capability of MiniVend. Not necessary if using StaticAll.

    StaticPage info/about_us info/terms_and_conditions

    StaticPath
    The path (relative to HTTP document root) which should be used in pages built with the static page-building capability of MiniVend.

    StaticPath /catalog

    StaticPattern
    A perl regular expression which is used to qualify pages that are to be built statically. The default is blank, which means all pages qualify.

    StaticPattern ^info|^help

    StaticSuffix
    The extension to be appended to a normal MiniVend page name when building statically. Default is .html. Also affects the name of pages in the MiniVend page directory -- if set to .htm the pages must be named with that extension.

    StaticSuffix .htm

    Sub
    Defines a catalog subroutine for use by the B<[perl sub] subname arg [/perl]> construct. Use the ``here document'' capability of MiniVend configuration files to make it easy to define:

        Sub <<EOF
        sub sort_cart {
            my(%items) = @_;
            my($item,$name);
            my $out = '<TABLE BORDER=1>';
            foreach $name (sort keys %items) {
                $out .= '<TR><TD>';
                $out .= $items{$name};
                $out .= '</TD><TD>';
                $out .= $name;
                $out .= '</TD></TR>';
            }
            $out .= '</TABLE>';
            return $out;
        }
        EOF
    
    

    As with Perl ``here documents'', the EOF (or other end marker) must be the ONLY thing on the line, with no leading or trailing white space. Do not append a semicolon to the marker.

    The above would be called with:

    [perl sub] sort_cart ( [item-list] "[item-description]", "[item-code]", [/item-list] ) [/perl]

    and will display an HTML table of the items in the current shopping cart, sorted by the description. (Using an alternative form of quoting such as q{ } will minimize problems with quotes in the passed parameters -- you may use any style you like, including here documents. Syntax errors will be reported to error.log .)

    Catalog subroutines may not perform unsafe operations -- the Safe.pm module enforces this.

    SubArgs
    Standard arguments that should be supplied to any routine with a name as defined.

    Defining

    SubArgs passwd values cgi

    and calling the routine with

    [perl sub] passwd ('[value username]', '[value password]) [/perl]

    is the same as calling

    [perl sub values cgi] passwd ('[value username]', '[value password]) [/perl]

    This can make calling routines more natural, and is especially useful in combination with mv_subroutine .

    TaxShipping
    A comma or space separated list of states or jurisdictions that tax shipping cost, i.e. UT. Blank by default, never taxing shipping.

    TaxShipping UT,NV,94024

    Tracking
    This option is removed in MiniVend 3.0. It will provide a warning, but will not stop the catalog from becoming operational.

    Most users now use the simpler and more flexible Easy ASCII Tracking capability.

    TransparentItem
    When set to the name of a product attribute (which must be defined in the directive UseModifier , and that attributes evaluates to true (yes, true, or 1, not case-sensitive), that item will not be shown on Item Lists .

    TransparentItem option

    UpsZoneFile
    The file containing the UPS zone information, specified relative to the catalog directory unless it begins with a /. It can be in the format distributed by UPS (for 1997, at least) -- or can be in a tab-delimited format, with the three-letter zip prefix of the customer used to determine the zone. It interpolates based on the value in mv_shipmode. A user database named the same as the mv_shipmode variable must be present or the lookup will return zero.

    UpsZoneFile /usr/minivend/data/ups_zone.asc

    UseCode
    This determines whether the part number field in the ASCII product file will be used to determine the link to the item for the [item_link] tag. If set, this has the effect of creating a different HTML page link for every part number. If not set (the default), the [item_link] tag uses the value of the last field in the ASCII product file as the link value. This option is largely deprecated by the on-the-fly page building facility.

    UseCode yes

    UseModifier
    Determines whether any attributes, the modifiers specified in the directive, can be attached to the item. See Item Attributes . The default is no modifier. Don't use a value of quantity -- it will not do what you want.

    UseModifier size,color

    Variable
    Defines a catalog variable that will be available in the current catalog with the notation __Variable__. Variable identifiers must begin with a capital letter, and can contain only word characters (A-Z,a-z,0-9 and underscore). These are substituted second (right after global Variables) in any MiniVend page, and can contain any valid MiniVend tags except global variables.

    Variable DOCUMENT_ROOT /usr/local/etc/httpd/htdocs

    .


    ADMINISTERING MINIVEND

    Many utilities are supplied in the VendRoot/bin directory:

    start Symbolic link to start_unix or start_inet stop Stops the server start_inet Starts the server in INET mode start_unix Starts the server in UNIX mode restart Symbolic link to restart_unix or restart_inet restart_inet Re-starts the server in INET mode restart_unix Re-starts the server in UNIX mode dump Dumps the session file for a particular catalog expire Expires sessions for a particular catalog reconfig Runtime reconfiguration of catalogs check Template script to monitor server health checkstat.sh Template script to monitor server upness htpasswd.pl Program to create .htpasswd files offline Does offline build of the database(s) update Does in-place update of the database(s) makecat Make catalog localize Help build a locale file from MiniVend pages

    Some thought should be given to where the databases, error logs, and session files should be located, especially on an ISP that might have multiple users sharing a MiniVend server. In particular, you might put all of the session files and logs in a directory that is not writable by the user -- if the directory or file is corrupted the catalog may go down.

    To test the format of user catalog configuration files before restarting the server, you can do (from VendRoot):

    minivend -test

    That will check all configuration files for syntax errors, which might otherwise prevent a catalog from coming up. Once a catalog configures properly, user reconfiguration will not crash it, just cause an error. But it must come up when the server is started.

    Starting, Stopping, and Re-starting the Servers

    The following commands need to have VENDROOT changed to the main directory where you installed MiniVend. If you made /home/minivend your MiniVend base directory, the start command would be /home/minivend/bin/start.

    To start the server:

    VENDROOT/bin/start or VENDROOT/bin/minivend -serve

    Assuming the server starts correctly, you will see the names of catalogs as they are configured, along with a message stating the process ID it is running under.

    To re-start the server:

    VENDROOT/bin/restart or VENDROOT/bin/stop; VENDROOT/bin/minivend -serve

    This is typically done to force MiniVend to re-read its configuration. You will see a message stating that a TERM signal has been sent to the process ID the servers are running under -- that information is also sent to /home/minivend/error.log. Check the error.log file for confirmation that the server has restarted properly.

    To stop the server:

    VENDROOT/bin/stop

    You will see a message stating that a TERM signal has been sent to the process ID the server is running under -- that information is also sent to /home/minivend/error.log.

    Because processes waiting for selection on some operating systems block signals, they may have to wait for HouseKeeping seconds to stop. The default is 60.

    UNIX and INET modes

    As of MiniVend 3.00, both UNIX-domain (the default) or INET-domain sockets can be used for communication. INET domain sockets are useful when more than one server, connected via a local-area network (LAN), is used for accessing a MiniVend server.

    IMPORTANT NOTE: When sending sensitive information like credit card numbers over a network, always ensure that the data is secured by a firewall, or that the MiniVend server runs on the same machine as any SSL-based server used for encryption.

    If you only want to run with one method of communication, use the -i and -u flags.

    # Start only in UNIX mode VENDROOT/bin/start -u # Start only in INET mode VENDROOT/bin/start -i

    User reconfiguration

    The individual catalogs can be reconfigured by the user by running the reconfig command. At least one check must be made to authenticate -- by coming from a particular host (see MasterHost ), having validated by HTTP basic authorization (see RemoteUser ), or by password entry (see Password ). The ideal way to use it is in combination with HTTP basic authorization to allow remote reconfiguration by web browser. It is possible at that point to have a completely FTP- and HTTP-configured catalog.

    A reconfig script is included with the demo catalogs, set up with the Password method of authentication and a blank password, suitable for the user to reconfigure the catalog from a Unix shell. To set it up as a CGI, use the MasterHost or RemoteUser authentication methods.

    Making the Product Database

    The DBM product databases can be built offline with the offline command. The directory to be used for output is specified either on the command line with the -d option, or is taken from the catalog.cfg directive OfflineDir -- offline in the catalog directory by default. The directory must exist. The source ASCII files should be present in that directory, and the DBM files are created there. Existing files will be overwritten.

    offline -c catalog [-d offline_dir]

    Updating Individual Records

    If you have a very large DBM database that takes a long time to build, you may want to use the bin/update script to change just one field in a record, or to add from a corrections list.

    The following updates the products database price field for item 19-202 with the new value 25.00

    update -c catalog -f price 25.00

    More than one field can be updated on a single command line

    update -c catalog -f price -f comment 25.00 "That pitchfork couple"

    The following takes input from file , which must be formatted exactly like the original database and adds/corrects any records contained therein.

    update -c catalog -i file

    Invoke the command without any arguments for a usage message describing the options.

    Expiring Sessions

    You should periodically expire old sessions to keep the session database file from growing too large.

    expire -c catalog

    You could add a crontab entry such as the following:

    # once a day at 4:40 am 40 4 * * * perl /home/minivend/bin/expire -c catalog

    MiniVend will wait until the current transaction is finished before expiring, so you can do this at any time without disabling web access. Any search paging files for the affected session (kept in ScratchDir ) will be removed as well.


    DEBUGGING

    As of version 3.06, MiniVend allows you to see debugging information based on the state of several controls.

    MiniVend comes with debugging output disabled by default -- this is for speed and code compactness. To enable debugging, change directory to the MiniVend root (the software directory) and run:

    # Must change to MiniVend software directory first! bin/ifdef -y -t DEBUG

    This only works for MiniVend 3.06 and above. Earlier MiniVend versions have only a crude debug available with the -D startup options.

    To disable, use the command

    # Must change to MiniVend software directory first! bin/ifdef -n -t DEBUG

    Note that some warnings may be generated by the debugging itself, typically ``use of unitialized variable'' warnings generated by undefined debug references. You can safely ignore these if they occur pointing to lines where the logDebug routine is called.

    -Dnnnn
    If you start MiniVend with the -D option, it will run in the foreground and extensive debug information will be output on the terminal that started the program. If nnnn, a numeric option set, is present, that debug level will be set. The default level is 4097, running in the foreground with only a few debug outputs (normal mode) present. If you want to run in the foreground with maximum information, use the level 4351.

    IMPORTANT NOTE: This may affect some program operations. If something new fails in debug mode, try it again in normal background server mode. In particular, changes to the configuration made on the fly in the page will stick since the process is not forked.

    [tag flag debug] level1 level2 ... [/tag]
    This sets the debug level in the page. If you want to see what is happening with a particular type of operation, the debug levels are:

    DESCRIPTION NUM TEXT DISABLE ----------- --- ----- ----- Disable all debug 0 off N/A Normal operations 1 normal !normal Tag interpretation 2 tag !tag Database operations 4 data !data Configuration info 8 config !config Search operations 16 search !search Session operations 32 session !session Server operations 64 server !server Cache/benchmark 128 cache !cache Show calling package 512 caller !caller Show in page comment 1024 comment !comment Place in mvdebug 2048 N/A N/A Run in foreground 4096 N/A N/A Verbose in HTML 2047 Verbose foreground 5119

    NOTE: The text levels only operate in conjunction with [tag flag debug].

    If you want to output the debug information embedded in an HTML comment at the end of the page you get from your browser, add level 1024. This overrides the output to mvdebug temporarily, or to foreground output indefinitely, if those are enabled.

    Use this to set verbose but no tag details, with output to HTML:

    [tag flag debug]comment verbose !tag[/tag]

    Use this to look at only database operations, with output to HTML:

    [tag flag debug]comment !verbose data[/tag]

    MINIVEND_DEBUG environment variable
    Prior to starting the server, you can determine the level to run at by setting the environment variable MINIVEND_DEBUG . It is an ANDed set of debug levels yielding a decimal number. For example, to show debug information in HTML comments with maximum verbosity, use one of the following command prior to starting the MiniVend daemons:

    # UNIX C-shell types (tcsh, csh, etc.) setenv MINIVEND_DEBUG 1279 # UNIX Bourn-shell types (bash, sh, ksh, etc.) MINIVEND_DEBUG=1279 export MINIVEND_DEBUG # Windows/DOS command box set MINIVEND_DEBUG=1279

    DebugMode directive
    The debug mode can be set both globally (in minivend.cfg ) and for each catalog (in catalog.cfg ) with the DebugMode directive, with levels as above.

    DisplayErrors
    To enable display of fatal errors (those things that would normally cause a 500 server error) then the DisplayErrors directive must be set to Yes in both minivend.cfg and catalog.cfg . Debug information will be included if available and level 1024 is set.

    The debug mode of 8192 will enable DisplayErrors for every catalog.

    .


    MANUAL INSTALLATION OF CATALOGS

    A MiniVend installation is complex, and requires quite a few distinct steps. That is why there is an interactive configuration script that is included with MiniVend -- it merely does automatically what is described below. It makes the process much easier, and will install the demo catalog. This configuration script has been tested on many UNIX systems.

    The installation program (makecat) can be used to install your own custom catalog template. See the supplied demo template simple for examples.

    Needed Directories

    The MiniVend program, and its supporting libraries, should all go into one directory as installed by the installation program.

    User catalog pages, user databases, and user configuration files should all go into their private directories. Because the catalog pages are served through the MiniVend cgi-bin program and contain nonstandard elements, they should not be put into a public WWW directory, nor do they need to have world-readable file permissions.

    IMPORTANT NOTE: As of MiniVend 2.0, since catalogs are all run under one server, permissions are complex and very important. Please let the MiniVend configuration program do the work!

    You will want a public WWW directory for in-line image graphic files. MiniVend does not serve the images, only the HTML tags calling them. A useful convention is to place all buttonbars, backgrounds, and icons in the /images directory, with the catalog items perhaps located in the /images/catalog directory. It is up to you, but remember that you must use an absolute path -- relative paths will not do. MiniVend 2.0 supports the ImageDir directive, which places that as the absolute path in front of all relative IMG and INPUT SRC specifications.

    You will need a cgi-bin directory in which to put the vlink or tlink program.

    The Demo Systems

    Sample catalog pages are in the directory simple/. If you would like to use them as a starting point for your own catalog, you can either have the configure script install the demo for you, or you can copy the files into the MiniVend directory and your HTML directory.

    To install the demo:

    bin/makecat simple

    Answer the prompts supplied by the program. Note that there are two types of paths asked for, URL paths like the /cgi-bin inside http://www.machine.com/cgi-bin/simple, and file paths that are complete fully-qualified file path names.

    Setting up VLINK and TLINK

    The vlink and tlink programs, compiled from vlink.c and tlink.c, are small C programs which contact and interface to a running MiniVend daemon. The vlink executable is normally made setuid to the user account which runs MiniVend, so that the UNIX-domain socket file can be set to secure permissions (user read-write only). It is normally not necessary for the user to do anything -- they will be compiled by the configuration program. If the MiniVend daemon is not running, either will display a message indicating that the server is not available. The following defines in the produced config.h should be set:

    LINK_FILE
    Set this to the name of the socket file that will be used for configuration, usually ``/usr/local/lib/minivend/etc/socket'' or the ``etc/socket'' under the directory you chose for the VendRoot.

    LINK_HOST
    Set this to the IP number of the host which should be contacted. The default of 127.0.0.1 (the local machine) is probably best for most installations.

    LINK_PORT
    Set this to the TCP port number that the MiniVend server will monitor. The default is 7786 (the ASCII codes for 'M' and 'V') and does not normally need to be changed.

    LINK_TIMEOUT
    Set this to the number of seconds vlink or tlink should wait before announcing that the MiniVend server is not running. The default of 45 is probably a reasonable value.

    .

    Compiling VLINK and TLINK

    Change directories to the src directory, then run the GNU configure script:

    cd src ./configure

    You will see some output as the configure script checks your system. Then compile the programs:

    cc vlink.c -o vlink cc tlink.c -o tlink

    You can ensure your C compiler will be invoked properly with this little ditty:

    perl -e 'do "syscfg"; system("$CC $LIBS $CFLAGS $DEFS -o tlink tlink.c");' perl -e 'do "syscfg"; system("$CC $LIBS $CFLAGS $DEFS -o vlink vlink.c");'

    On some systems you can make the executable smaller with the strip program. But don't worry about it if strip is not on your system.

    strip vlink strip tlink

    If you want MiniVend to run under a different user account than your own, make that user the owner of vlink. (You probably need to be root to do this). Do not make vlink owned by root, because making vlink setuid root is an huge and unnecessary security risk. It should also not normally run as the default WWW user (often nobody or http)).

    chown minivend vlink

    Move the vlink executable to your cgi-bin directory:

    mv vlink /the/cgi-bin/directory

    Make vlink setuid:

    chmod u+s /the/cgi-bin/directory/vlink

    Most systems unset the SUID bit when moving the file, so you should change it after moving.

    The SCRIPT_NAME as produced by the HTTP server must match the name of the program. (As usual, you should let the makecat program do the work.)


    AUTHOR

    Mike Heins, mike@minivend.com.


    ACKNOWLEDGEMENTS

    Original author of Vend was Andrew Wilcox. MiniVend was based on Vend 0.2, with portions from Vend 0.3.