MiniVend -- shopping cart and electronic catalog system
This document describes MiniVend 3.15, based on Andrew Wilcox's original Vend, Version 0.2, with portions from Vend 0.3. This is the third major revision of MiniVend.
MiniVend is a database access and retrieval system focused on e-commerce. It allows customers to select items to buy from catalog pages. The program tracks which products they have selected and the quantity desired. Many different catalog pages may be visited, and the user ``session'' will be tracked to build a cumulative list of items. Once selection is finished, they may complete the ordering process by entering their name and address along with payment information, if any. Once the order process is completed, MiniVend submits the order to the system via email or an external order entry program.
Though its name begins with ``Mini'', MiniVend is anything but. It is a high-end, fully customizable, powerful software system with complete database functionality. It is suitable for many applications besides shopping carts, though that is its main bent.
MiniVend plugs into a system with an SSL (Secure Sockets Layer) server, allowing encrypted transmission of sensitive customer data. This capability makes the entry of credit card numbers practical and secure. In addition, it supports online payment systems and encryption; no credit card numbers need be stored on the system ``en clair''.
Many different catalogs can be run from the same MiniVend server, allowing an ISP to serve many different customers from one or just a few MiniVend server processes. As many as 1,000 MiniVend catalogs have been run on one machine from the same server process.
When possible, multiple servers are forked to serve the same set of catalogs. This ensures fast response, while only one server runs when there is no catalog activity.
MiniVend is powerful, and correspondingly complex. It can easily handle catalogs of a million items or more, with excellent performance. It has completely flexible page display, search, and order entry capability. If you only have a few items to catalog, MiniVend is probably overkill for your needs. But if you are willing to spend some up-front learning time, it can support your simple catalog with unlimited room to grow. To get a fast start with a simple catalog, start with the simple demo and customize from there.
The following section describes how MiniVend works, and should be read by anyone creating a MiniVend catalog.
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]
or
<IMG SRC=``somepic.gif'' MV=``[embedded in
HTML]''>, are interpreted by MiniVend and many different values can be substituted. Some examples are:
[value input_field]
tag. The input_field
is a normal
HTML form field.
[data table=products column=name key=334-12]
.
[data session referer]
), domain they are from ([data session host]
), source of hit in a partner program ([data session source]
), the time of their last access ([data session time]
), and many other parameters.
[file directory/file]
or [include directory/file]
, or the output from an arbitrary program (given proper permission from
your administrator!).
There are over 80 different distinct tags supporting hundreds of functions.
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 CGI link program (generically 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, which is a regular CGI program, calls the MiniVend server through a socket. 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 find or order items from your catalog.
The user clicks on the link and MiniVend looks in the 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 real-time electronic payment 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.
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:
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:
MiniVend is normally free of charge, and is distributed under the GNU general public license. This means that individuals and organizations, both commercial and non-commercial, may use MiniVend without charge. If you modify and redistribute it, there are certain obligations you must fulfill. See the file Copying which came with your MiniVend distribution for the full license.
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, or use the MiniVend mail list and hope that someone will help you.
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
.
You will need Perl version 5.004 or higher to run MiniVend 3.15. 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. See
http://www.perl.com/CPAN/
Windows users will need to obtain the either the ActiveState Perl build 5xx (the one from the
NT Resource Kit will
NOT work) or the standard version Perl, also known as the
Gurusamy Sarathy or CORE version, from the directory ports/win32/Standard/x86
.
MiniVend requires a that a web server be installed on your system in the normal course of events; it does have an internal server which can be used for administration, testing, and maintenance, but you will not want to use it to serve images and other content.
As detailed previously, MiniVend is always running in the background as a daemon. It monitors either 1) a UNIX-domain file-based socket, located in the etc/ subdirectory; or 2) a series of INET-domain sockets. The small CGI link program, called in the demo simple, is run to connect to one of those sockets and provide the link between your browser.
NOTE: Since Apache and other CERN/NCSA-derived servers are the most popular, we will talk in the terms they use. If you use another web server, you may have to translate the terms; for instance on
MS Personal web server the standard
ScriptAlias
is /scripts
.
You need to have a ScriptAlias
or other
CGI execution capability to use the link program. (The
default ScriptAlias
for many web servers is /cgi-bin
.) If you have ExecCGI
set for all of your directories, then any program ending in a particular
file suffix (usually
.cgi) will be seen as a
CGI program.
MiniVend, by convention, names the link program the same name as the catalog
ID. In the distribution demo, this would yield a program name or
SCRIPT_PATH of
/cgi-bin/simple
or /simple.cgi
. This
SCRIPT_PATH is used to determine which MiniVend
catalog will be used when the link program is accessed.
This is a socket which is not reachable from the Internet directly, but
which must come from a request on your own server. The link program
vlink
is the provided facility for such communication with MiniVend.
This is the most secure way to run your catalog, for there is no way for systems on the Internet to interact with MiniVend except through its link program.
The most important issue with UNIX-domain sockets on MiniVend is the permissions with which the CGI program and the MiniVend server run.
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.
These are sockets which are reachable from the Internet directly. The link
program tlink
is the provided facility for such communication with MiniVend; you may also
use your browser to talk to the socket directly if you have it mapped to a
catalog with the global TcpMap directive.
To improve security, MiniVend usually checks that the request comes from one of a limited number of systems, defined in the global TcpHost directive. (This check is not made for the internal HTTP server.)
If you contact the socket directly (only for INET-domain sockets), MiniVend will perform the HTTP server function itself, talking directly to the browser. It can monitor any number of ports and map them to a particular catalog; by default it only maps the special catalog mv_admin, which performs administrative functions. The default port is 7786 (ASCII for M an V), which is the default compiled into the distribution tlink program. You can change this port via the TcpMap directive.
To prevent catalogs that do not wish access made in this way from being served from the internal server, MiniVend has a fixed
SCRIPT_PATH of
/catalogname
(/simple for the distribution demo) which needs to be placed as an alias in
the Catalog directive to enable access. See TcpMap for more details.
Obtain, decompress and untar the distribution:
gzip -dc minivend-3.15.tar.gz | tar xvf -
NOTE FOR WINDOWS: Windows users need to unzip the file WinZip or a similar program 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.15
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 If something goes wrong. Otherwise, MiniVend should be installed at the completion of the script. It is strongly suggested that you install the demo catalogs as a starting point for your own catalog -- in fact you will not be able to run MiniVend until you have created a catalog.
You 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.
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:
config/static.pages
will be read when the directive
StaticPage <static.pages
is encountered in the catalog.cfg file.
This directory also contains template information used with the makecat program.
/cgi-bin/simple/products/gold
will call the page in the file pages/products/gold.html
.
The supplied makecat
script, which is in the MiniVend program directory
bin
, is designed to set up a catalog based on your server configuration. It interrogates the user for parameters like the directories to use,
URL to base the catalog in,
HTTP server definitions, and file ownership. It is self-documenting in that it asks verbose questions and gives relevant examples.
The makecat
script needs a template catalog to operate on. The
simple and flycat demo templates are distributed with MiniVend -- there is also an older sample frame-based demo catalog available at
ftp.minivend.com
.
IMPORTANT NOTE: You only make a catalog once. All further configuration is done by editing the files within the catalog directory.
A catalog template contains an image of a configured
catalog. The best way to see what the makecat program does is to configure
the simple demo and then run a recursive diff
on the template and configured catalog directories:
diff -r mvend/simple catalogs/simple
NOTE: diff
is usually only available on
UNIX.
You will see that the files are mostly the same, except that certain macro
strings have been replaced with the answers you gave to the script. For
example, if you answered www.mydomain.com
at the prompt for server name, then you would see this difference in the
catalog.cfg file:
# template Variable SERVER_NAME __MVC_SERVERNAME__
# configured catalog Variable SERVER_NAME www.mydomain.com
The macro string __MVC_SERVERNAME__ was substituted with the answer to the question about server name. In the same way, other variables are substituted, and include (at least):
MVC_BASEDIR MVC_IMAGEDIR MVC_CATROOT MVC_IMAGEURL MVC_CATUSER MVC_MAILORDERTO MVC_CGIBASE MVC_MINIVENDGROUP MVC_CGIDIR MVC_MINIVENDUSER MVC_CGIURL MVC_SAMPLEHTML MVC_DEMOTYPE MVC_SAMPLEURL MVC_DOCUMENTROOT MVC_VENDROOT MVC_ENCRYPTOR
(Not all of these are present in the simple or sample templates.) In fact, any environment variable that is set and begins with
MVC_ will be substituted for by the
makecat
script. So if you wanted to set up a configurable parameter to customize the
COMPANY variable in catalog.cfg, you could run a pre-qualifying script that set the environment variable
MVC_COMPANY and then place in the catalog.cfg file:
Variable COMPANY __MVC_COMPANY__
All files within a template directory are substituted for macros, not just
the catalog.cfg file. There are two special directories named html
and images
. These will be recursively copied to the directories defined as SampleHTML
and ImageDir.
IMPORTANT NOTE: The template directory is located in the MiniVend software directory, i.e.
where minivend.cfg
resides. You normally do not edit files in the template directory. If you
want to try creating your own template, it is recommended that you name it
something besides simple and copy the simple demo directory to it as a starting point. Templates are normally placed in
the MiniVend base directory, but can be located anywhere -- the script will
prompt you for location if it cannot find a template.
In addition to the standard parameters prompted for by MiniVend, and the standard catalog creation procedure, you may define four other files in the config directory of the template:
additional_fields -- file with more parameters for macro substitution additional_help -- extended description for the additional_fields pre_commands -- commands passed to the system prior to catalog copy post_commands -- commands passed to the system after catalog copy
All files are paragraph-based; in other words, a blank line (with no spaces) terminates the individual setting.
The additional_fields file contains:
PARAM The prompt. Set PARAM to? The default value of PARAM
This would cause a question during makecat:
The prompt. Set PARAM to?.....[The default value of PARAM]
If the additional_help file is present, you can give additional instructions for PARAM.
PARAM These are additional instructions for PARAM, and they may span multiple lines up to the first blank line.
The prompt would now be:
These are additional instructions for PARAM, and they may span multiple lines up to the first blank line.
The prompt. Set PARAM to?.....[The default value of PARAM]
If the file config/pre_commands exists, it will be read as a command followed by the prompt/help value.
mysqladmin create __MVC_CATALOGNAME__ We need to create an SQL database for your Minivend database tables. This will cause the prompt:
We need to create an SQL database for your Minivend database tables. Run command "mysqladmin create simple"?
If the response is ``y'' or ``yes'', then the command will be run by passing it through the Perl system()
function. As with any of the additional configuration files,
MVC_PARAM macro substitution is done on the command and help. Obviously you must have proper permissions for the command.
The file config/post_commands is exactly the same as pre_commands except you are prompted after the catalog files are copied and macro substitution is performed on all files.
MiniVend has multiple catalog capability, and therefore breaks the
configuration files into two pieces. One is global (minivend.cfg
) and affects every catalog running under it. The other (catalog.cfg
) is specific to an individual catalog, and has no effect on other
catalogs.
The global minivend.cfg
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 defines the catalogs will be created at server startup.
The Catalog directive is often set up by the makecat
program, which can be used to configure a catalog.
Here is an example Catalog directive:
Catalog simple /home/catalogs/simple /cgi-bin/simple /secure-bin/simple
There may also be SubCatalog directives:
SubCatalog easy simple /home/catalogs/simple /cgi-bin/easy
easy.cfg
.
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''.
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 setup. In fact, in the over two years of MiniVend's existence many 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 an 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:
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.
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 660 or 770 mode, and you
should have no problems with permissions, and no problems with security.
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.
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.
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:
[if file file.gif] TAG [/if]
construct).
Small, Medium, Large, XL
You can also define any other attribute information in a database field.
[loop item]
tag, you could build product subclasses and accessory sets.
By default, all database source files are located in the in the
products subdirectory of the catalog directory. The main products database we
discussed above is in the file products/products.asc
by default. If you use one of the internal database methods, then any changes that are made to the
ASCII source file will be reflected in the database on the next access by a user. If you have a very large database, this may not be what you want -- it can take some time to build a large database. If you have less than a thousand records like the ones shown above in your products database, you normally need not worry -- updates will be almost instantaneous. (See
NoImport if you wish to stop auto updating.)
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 the search result page. To display information about single items, use the flypage.html template. You can customize these pages in many ways, and you can even use different templates for different types of products -- 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:
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.
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 most important thing to remember is that if you are supporting browsers which might not accept cookies, you must never send the user to a page that is not served by MiniVend. If you do, they will lose their session (and items in their shopping cart).
If you are using MiniVend's frames mode, you must be careful to source all frame panes from a page served by MiniVend. If you do not, then you may find the user has multiple session IDs depending on which frame the link came from.
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.
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 (new tags mode only) 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-alternate Alternation for table/line build /item-alternate 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-alternate Alternation for table/line build /loop-alternate 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-alternate Alternation for table/line build /sql-alternate 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 Show element from returned SQL queries. 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 userdb Access user database functions 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 and ImageDirSecure directives) 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.
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.
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]
).
* indicates an optional argument
[value field]
HTML examples:
<PARAM MV="value name"> <INPUT TYPE="text" NAME="name" VALUE="[value name]">
Expands into the current value of the customer/form input field named by
field.If the set
value is present, the form variable value will be set to it and the new value returned. Use this to ``uncheck'' a checkbox or set other form variable values to defaults. If
HIDE is set, the value will be set but not returned to the page.
If escaped
is 1, single quotes will be escaped with a backslash; this allows you to
contain the [value ...] tag within single quotes. (It is somewhat better to use other Perl quoting
methods like q{[value whatever]}
.)
When the value is returned, any MiniVend tags present in the value will be escaped. This prevents users from entering MiniVend tags in form values, which would be a serious security risk.
positional: [page dir/page arg*] (only two positional parameters)
HTML example: <A MV=``page'' MV.HREF=``dir/page'' MV.ARG=``arg''* HREF=``dir/page.html''>
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.
If the user has sent a cookie to MiniVend (meaning the second page they access), and you set the scratch value c<mv_no_session_id> in their session, the session
ID will not be appended to the
URL. If you set the scratch value
mv_no_count
, then the page count will not be appended; this is not dependent on
cookies. So if you put in your initial page
[set mv_no_session_id]1[/set] [set mv_no_count]1[/set]
no session ID or count will be shown. That makes the URL shown above be http://machine.company.com/cgi-bin/vlink/shirts -- once again, that is on the second page the user accesses if they are taking and sending cookies. If the user has a pre-existing MV_SESSION_ID cookie from a prior session, the effect will be immediate.
The 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, which is the default, 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 plain HTML 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.
The optional form
argument allows you to encode a form in the link.
[page form=" mv_order_item=99-102 mv_order_size=L mv_order_quantity=1 mv_separate_items=1 mv_todo=refresh"] Order t-shirt in Large size </A>
The two form values mv_session_id and mv_arg are automatically added when appropriate. (mv_arg is the arg parameter for the tag.)
If the parameter href
is not supplied, process is used, causing normal MiniVend form processing. If the href
points to an http:// link no MiniVend
URL processing will be done, but the mv_session_id
This would generate a form that ordered item number 99-102 on a separate
line (mv_separate_items
being set), with size L
, in quantity 2. Since the page is not set, you will go to the default
shopping cart page -- equally you could set mv_orderpage=yourpage
to go to yourpage
.
You must have TolerateGet set (which is the default) and all normal MiniVend form caveats apply -- you must have an action, you must supply a page if you don't want to go to the default, etc.
You can theoretically submit any form with this, though none of the included values can have newlines or trailing whitespace. If you want to do something like that you will have to write a UserTag.
You can also use it for submitting foreign forms if you like; it will not touch the href if it begins with http:, ftp:, or the like.
positional: [area pg arg*]
HTML example: <A MV=``area dir/page'' HREF=``dir/page.html''>
Produces the
URL to call a MiniVend page, without the surrounding
A
HREF notation. This can be used to get control of your
HREF items, perhaps to place an
ALT string or a Javascript construct. It was originally named
area
because it also can be used in a client-side image map.
<A HREF="[area catalog]" ALT="Main catalog page">
The optional arg is used just as in the page tag.
The optional form
argument allows you to encode a form in the link.
<A HREF="[area form=" mv_order_item=99-102 mv_order_size=L mv_order_quantity=1 mv_separate_items=1 mv_todo=refresh" ]"> Order t-shirt in Large size </A>
See above for more information.
[page shirts]Our shirt collection[/page].
TIP: A small efficiency boost in large pages is to just use the </A> tag.
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="code" href="cart/page" base="database"]
HTML example: <A MV=``order code'' HREF=``ord/basket''>
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.
Note that this is the same as:
Order a [page order TK112]Toaster</A> today.
You can change frames for the order with:
Order a <A HREF="[area order TK112]" TARGET=newframe>Toaster</A> today.
[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.
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!
MiniVend, as with most powerful shopping cart programs, is all about databases.
NOTE: No other database besides MiniVend's internal one is needed. You may find that keeping your database in an SQL manager makes it easier to integrate MiniVend with other tools. MiniVend is fully buzzword-equipped, but if you just want to maintain a spreadsheet with your product information, you can ignore the references to SQL, DBI, DBD, and all of those other things and just modify the file products.asc appropriately.
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.
NOTE: In the following descriptions, we will use the following terms interchangeably:
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.
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.
code description price image SH543 Men's fine cotton shirt 14.95 shirts.jpg
|
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
"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:
[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.
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.
IMPORTANT NOTE: The field names must be on the first line of the
products.asc
file. These field names must match exactly the field names of the [item-field]
tags in your catalog pages, or the MiniVend server will not access them
properly. Field names can contain the characters A-Za-z0-9, along with hyphen (-
), underscore (_
), pound sign/hash mark (#
), slash (/
), and period (.
).
As of MiniVend 3.0, more than one database may be used as a products
database. If the catalog directive ProductFiles is set to a space-separated list of valid MiniVend database identifiers,
those databases will be searched (in the order specified) for any items
that are ordered, or for product information (as in the [price code]
and [field code]
tags).
When the products.asc file changes after import or edit, the DBM database is re-built upon the next user access. No restart of the server is necessary.
If changing the database on the fly, it is recommended that you lock the file while it is being modified.
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 separates the record. Watch those carriage returns! Also has a special format when CONTINUE is set to be NOTES. 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.
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:
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.
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.
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.
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.
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. (You won't want to use NOTES unless using type LINE.)
\
) 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 databases.
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.
LINE is a special setting so that you can use a multi-line field. Normally, when using the LINE type, you may have only data on one line separated by one blank line. When using CONTINUE LINE, you may have some number of fields which are each on a line, while the last one spans multiple lines up until the first blank line.
Example in catalog.cfg:
Database products products.asc LINE Database products CONTINUE LINE
Products.asc file:
code price description 00-0011 500000 The Mona Lisa, one of the worlds great masterpieces. Now at a reduced price! 00-0011a 1000 A special frame for the Mona Lisa.
NOTES reads a Lotus Notes ``structured text'' file. The format is that there are any number of fields, all except one of which must have a field name followed by a colon and then the data. There is optional whitespace after the colon.
Records are separated by a settable delimiting charater which goes on a line by itself, much like a ``here document''. By default it is a form feed (^L) character.
The final field begins at the first blank line and continues to the end of
the record. This final field is named notes_field
unless you set it as mentioned below.
MiniVend reads the field names from the first paragraph of the file. The
key field should be first, followed by other fields in any order. If one
(and only one) field name has whitespace, then its name is used for the notes_field
and any characters after a space or
TAB are used as the record delimiter. If there are none, then the delimiter returns to the default form feed
(^L) and the field name reverts to
notes_field
. The field in question will be discarded, but a second field with
whitespace will cause an import error.
Following records are then read by name, and only fields with data in them
need be set. Only the notes_field
may contain a newline. It is always the last field in the record, and
begins at the first blank line.
The following example sets the delimiter to a tilde (~)
and renames the notes_field
to description.
Example in catalog.cfg:
Database products products.asc LINE Database products CONTINUE NOTES
Products.asc file:
code title price image description ~ size color title: Mona Lisa price: 500000 code: 00-0011 image: 00-0011.jpg The Mona Lisa, one of the worlds great masterpieces. Now at a reduced price! ~ title: The Art Store T-Shirt code: 99-102 size: Medium, Large*, XL=Extra Large color: Green, Blue, Red, White*, Black price: 2000 Extra large 1.00 extra. ~
Database products EXCEL 1
This is normally used only with TAB-delimited files.
MiniVend will automatically build index files for a fast binary search of an individual field. This type of search is useful for looking up the author of a book based on the beginning of their last name, a book title based on its beginning, or other analagous situations.
Such a search requires a dictionary ordered index with the field to be
searched contained in the first field and the database key (product code)
in the second field. If you specify the INDEX field
modifier MiniVend will build the index upon database import:
Database products products.asc TAB Database products INDEX title
If the title
field is the fourth column in the products database table, a file products.asc.4
will be built, containing two tab-separated fields something like:
American Gothic 19-202 Mona Lisa 00-0011 Sunflowers 00-342 The Starry Night 00-343
The fast binary search is described in greater detail below -- see THE SEARCH ENGINE.
MiniVend's memory-based databases are the fastest possible way to organize and store data you will frequently use. To force a database to be built in memory instead of DBM, use the MEMORY modifier:
Database country country.asc TAB Database country MEMORY 1
Obviously large tables will use a great deal of memory, and the data will need to be re-imported from the ASCII source file at every catalog reconfiguration or MiniVend restart. The big advantage of using MEMORY is that the database remains open at all times and does not need to be reinitialized at every connect -- use it for smaller tables that will be frequently accessed.
The MEMORY modifier forces IMPORT_ONCE.
The IMPORT_ONCE modifier tells MiniVend not to re-import the database from the ASCII file every time it changes. Normally, MiniVend does a comparison of the database file modification time with the ASCII source every time it is accessed, and if the ASCII source is newer it will re-import the file. IMPORT_ONCE tells it only to import on a server restart or catalog reconfiguration:
Database products products.asc TAB Database products IMPORT_ONCE 1
SQL databases don't normally need this -- they will only be imported once in normal operation. Also see NoImport for a way to guarantee that the table will never be imported.
IMPORT_ONCE is always in effect for MEMORY databases. Do a catalog reconfiguration to force a change.
You might often want to add a data record to a database as a result of an
order or other operation. Use MiniVend's [import ...]
tag.
[import table=table_name file=filename* type=(TAB|PIPE|CSV|%%|LINE)* continue=(NOTES|UNIX|DITTO)* separator=c*]
Import one or more records into a database. The type is any of the valid MiniVend delimiter types, with the default being defined by the setting of Delimiter. The table must already be a defined MiniVend database table; it cannot be created on the fly. (If you need that, it is time to use SQL.)
The import type selected need not match the type the database was specified; different delimiters may be used.
The type of LINE
and continue
setting of NOTES
is particularly useful, for it allows you to name your fields and not have
to remember the order in which they appear in the database. The following
two imports are identical in effect:
[import table=orders] code: [value mv_order_number] shipping_mode: [shipping-description] status: pending [/import] [import table=orders] shipping_mode: [shipping-description] status: pending code: [value mv_order_number] [/import]
The code or key must always be present, and is always named code.
If you do not use NOTES
mode, you must import the fields in the same order as they appear in the
ASCII source file.
The file option overrides the container text and imports directly from a named file based in the catalog directory. Careful, if you want to import from products.asc
you must specify
file="products/products.asc"
. If the NoAbsolute directive is set to Yes
in minivend.cfg, only relative path names will be allowed.
The [import ....] TEXT [/import]
region may contain multiple records. If using NOTES
mode, you must use a separator, which by default is a form-feed character
(^L). See Import Attributes above for more information.
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.
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 databases can be written in the normal course of events, either
using the [import ...]
tag or with a tag like
[data table=table column=field key=code value=new-value]
.
If you wish to control writing of a global database, or to a certain catalog within a series of subcatalogs, or make one read only, you can do so.
To enable write control:
Database products WRITE_CONTROL 1
Once that is done, you can make a database read only, which won't allow
writing even if [tag flag write]products[/tag]
is specified:
Database products READ_ONLY 1
If you want to have control with [tag flag write]products[/tag]
:
Database products WRITE_TAGGED 1
If you want to limit write to certain catalogs, you can set:
Database products WRITE_CATALOG simple=0, sample=1
The ``simple'' catalog will not be able to write, while ``sample'' will if [tag flag write]products[/tag]
is enabled.
If you want a database to be always writable without having to specify [tag flag write] ... [/tag]
, then you can define:
Database products WRITE_ALWAYS 1
The default behavior of SQL datbases is equivalent to WRITE_ALWAYS, while the default for GDBM_File, DB_File, and Memory databases is equivalent to:
Database products WRITE_CONTROL 1 Database products WRITE_TAGGED 1
If you have a database you want to make available to all catalogs on the MiniVend server instance, you may define a database in minivend.cfg. Any catalog running under that server will be able to use it. Careful; it is writable by any catalog unless you use WRITE_CONTROL.
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.
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.
MiniVend now provides complete external SQL database support via the Perl DBI and DBD modules. This allows transparent access to any database engine 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):
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.
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.
[item-data ...]
, [loop-data ...]
, [item-field ...
, etc. Typically used for Oracle and some other
SQL implementations.
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), discount=float Database products COLUMN_DEF author=char(40), title=char(64) Database products COLUMN_DEF nontaxable=char(3) Database products NUMERIC price, discount
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.
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 interpolate=1]
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 .= "<BR>"; } $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 interpolate=1]
my $string =<<'EOF'; [sql type=hash base=arbitrary]select * from arbitrary where code <= '19'[/sql]
EOF my $hash = eval $string; my $out = ''; my $key; foreach $key (keys %$hash) { $out .= $key->{field1}; $out .= "<BR>"; } $out;
[/perl]
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 type=set base=orders interpolate=1] 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]
The values entered by the user are escaped, which prevents errors if quote characters have slipped into their entry.
[sql param] SQL [/sql identifier*]
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.
This tag is deprecated.
[sql html] SQL [/sql identifier*]
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 type=html]select * from arbitrary where code > '19' order by field2[/sql] </TABLE>
<TABLE BORDER=2> <TR><TH><B>SKU</B></TH><TH><B>Description</B></TH><TH><B>Price</B></TH> [sql type=list query="select code,desc,price from arbitrary where code > '19' order by field2"] <TR> <TD>[page [sql-code]][sql-code]</A></TD> <TD>[sql-param desc]</TD> <TD>[sql-param price]</TD> </TR> [/sql] </TABLE>
This is the fastest way to return data from an SQL query.
It uses the same tags as in the [loop ....]
, except prefixed with sql
. Available are the following, in order of interpolation:
[sql-param n] Field n of the returned query (in the row) [sql-param name] Field "name" 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-alternate n] Alternating text [/sql-alternate] Terminator for above [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
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.
To build complex order forms and reports, MiniVend has a complete tag language with over 80 different functions. It allows you access to and control over any of an unlimited number of database tables, multiple shopping carts, user name/address information, discount, tax, and shipping information, search of files and databases, and much more.
There is conditional capability with the [if ...]
text [else]
else-text
[/else][/if]
construct. It allows for testing for a condition within the MiniVend 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. [and ...]
,
[or ...]
and [elsif ...]
are also supported.
Most of the tests use Perl code, but MiniVend uses the Safe.pm module with its default restrictions to help ensure that improper code will not crash the server or modify the wrong data.
Perl can also be embedded with in the page, and if given the proper permission by the system administrator, can call upon resources from other computers and networks.
MiniVend uses a style similar to HTML, but with [square brackets] replacing <chevrons>. The parameters that can be passed are much the same, where a parameter=``paramter value'' can be passed.
IMPORTANT
NOTE: You must set the
NewTags catalog directive to Yes
in catalog.cfg
, which should be the default in any catalog template starting at MiniVend
3.07. If it is not set, or is set to No
, you will find that the behavior will not match this documentation!
Summary:
[tag parameter] Tag called with positional parameter [tag parameter=value] Tag called with named parameter [tag parameter="the value"] Tag called with space in parameter [tag 1 2 3] Tag called with multiple positional parameters [tag foo=1 bar=2 baz=3] Tag called with multiple named parameters [tag foo=`2 + 2`] Tag called with calculated parameter [tag foo="[value bar]"] Tag called with tag inside parameter [tag foo="[value bar]"] Container text. Container tag. [/tag]
Most tags can accept positional parameters; this speeds up parsing and is simpler to write in many cases.
Here is an example tag:
[value name=city]
That will cause MiniVend to look in the user form value array and return
the value of the form parameter city
, which might have been set with:
City: <INPUT TYPE=text NAME=city VALUE="[value city]">
Note that we pre-set the value with the previous value of city
(if any). It uses the positional style -- name is the first positional parameter for the [value ...] tag.
Positional parameters cannot be derived from other MiniVend tags; for instance [value [value formfield]] will not work. But if you use the named parameter syntax, the parameters can contain other tags, i.e.:
[value name="[value formfield]"]
There is one exception to the above rule when using the [item-list], [loop ...], [sql ...], and other list tags. We will examine that in their individual sections.
Many MiniVend tags are container tags:
[set Checkout] mv_nextpage=ord/checkout mv_todo=return [/set]
Tags and parameter names are not case sensitive, so [VALUE NAME=something] would work just as well. MiniVend convention is to place HTML tags in upper case and MiniVend tags in lower case so pages are easier to read, but you could easily reverse the sense.
Single quotes work just as well as double quotes, and can prevent ambiguity.
[value name=b_city set='[value city]']
works just as well.
Backticks, the other single quote, cause the parameter contents to be
evaluated as Perl code via the [calc]
tag. (This is in
MV3.15 and above.) So
[value name=row_value set=`$row_value += 1`]
is the same as
[value name=row_value set="[calc]$row_value += 1[/calc]"]
You can also specify constructs inside an HTML tag:
<TABLE MV="if items"> <TR MV="item-list"> <TD> [item-code] </TD> <TD> [item-description] </TD> <TD> [item-price] </TD> </TR></TABLE>
The above will loop over any items in the shopping cart, displaying their part number, description, and price, but only IF there are items in the cart. It is equivalent to:
[if items] <TABLE> [item-list] <TR> <TD> [item-code] </TD> <TD> [item-description] </TD> <TD> [item-price] </TD> </TR> [/item-list] </TABLE> [/if]
This is provided to allow
HTML editors to work with MiniVend if they wish. One
common tag that is best specified in this fashion is [body n]
, which would be best done as
<BODY MV=``body 1''>.
What is done with the results of the tag depends on whether it is a
container or standalone tag.
A container tag is one which has an end tag, i.e. [tag] stuff [/tag]
.
A standalone tag has no end tag, as in [area href=somepage]
. (Note that [page ...]
and [order ..]
are not container tags.)
A container tag will have its output re-parsed for more MiniVend tags by default. If you wish to inhibit this behavior, you must explicitly set the attribute reparse to 0. (Prior to MiniVend 3.09, reparse did not exist.) Note that you will almost always wish the default action.
With some exceptions ([include]
and [buttonbar ..]
among them) the output of a standalone tag will not be re-interpreted for
MiniVend tag constructs.
Most container tags will not have their contents interpreted before being
passed the container text. Exceptions include [calc]
.. [/calc]
and
[currency]
... [/currency]
. 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]
.
If you started using MiniVend prior to version 3.07, you may find that your catalog is structured in the [old] style.
MiniVend in old mode 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
Using the old parser is now strongly discouraged. You will find that you cannot use many of MiniVend's features.
If you have regions of the page which work under the old style and fail
with the new style, you can surround them with [compat] [/compat]
tag pair. This will evaluate that region only with the old style repeated
interpolation.
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.
The [data ...] and [field ...] tags access elements of MiniVend databases. They are the form used outside of the iterating lists, and can be effectively 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
The [field ...] tag is special in that it looks in any of the tables
defined as ProductFiles
, in that order, for the data, returning the first non-empty value. In most
catalogs, where ProductFiles
is not defined (i.e. the demo), [field title 00-0011]
is equivalent to
[data products title 00-0011]
.
[data base="database" field="field" key="key"
value="value" op="increment]
)
HTML example: <PARAM MV=data MV.TABLE=database MV.COL=field MV.ROW=key>
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 via UserDB 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 (UserDB)
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 code="code" name="fieldname"]
HTML example: <PARAM MV=field MV.COL=column MV.ROW=key>
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.
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 name="variable"] value [/set]
HTML example: <PRE MV=``set variable''> value </PRE>
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 You must give us your name. address=required Oops! No address. [/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">
Sometimes you want to use a form value that the user has set, but want it
to be initialized if not already present. The [default ...]
tag will do that.
Other times, you want to initialize a variable based on a database value.
The [lookup ...]
tag will perform a lookup in an arbitrary database and set return that
value only if the user form value is not set.
[default name="variable" default="default value" set=1*]
HTML example: <PARAM MV=``default'' MV.NAME=variable MV.DEFAULT=``default'' MV. set=1>
Returns the value of the user form variable variable
if it is non-empty. Otherwise returns default
, which is the string ``default'' if there is no default supplied. Got
that?
If the flag set
is present and non-zero, then the variable will be set to the default
and no value returned to the page. This allows you to initialize things like country, shipping mode, and
other values on a checkout page.
[lookup table="database" col="column" key=row value="[value name]"]
This is essentially same as the following:
[if value name] [then][value name][/then] [else][data database column row][/else] [/if]
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 with="-a"* arg="item item item" search="se=whatever"]
HTML example:
<TABLE><TR MV="loop 1 2 3"><TD>[loop-code]</TD></TR></TABLE>
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.
You can do an arbitrary search with the search=``args'' parameter, just as in a one-click search:
[loop search="se=Americana/sf=category"] [loop-code] [loop-field title] [/loop]
The above will show all items with a category containing the whole world ``Americana'', and will work the same in both old and new syntax.
NOTE: This tag does not nest with other [if-loop-data ...]
tags.
NOTE: This tag does not nest with other [if-loop-field ...]
tags.
[else]NOT DIVISIBLE TEXT[/else]
is present, then the
NOT
DIVISIBLE
TEXT will be displayed.
For example:
[loop-alternate 2]EVEN[else]ODD[/else][/loop-alternate] [loop-alternate 3]BY 3[else]NOT by 3[/else][/loop-alternate]
[on-change]
but within loop lists.
ProductFiles
, in that order, for the data, returning the value only if that key is
defined. In most catalogs, where ProductFiles
is not defined (i.e. the demo), [loop-field title]
is equivalent to
[loop-data products title]
.
Evaluates to the field name fieldname in the database, for the current item.
[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][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.
[if type="type" term="field" op="op" compare="compare"]
[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, and combine conditions:
[if value name =~ /^mike/i] This is the if with Mike. [elsif value name =~ /^sally/i] This is an elsif with Sally. [/elsif] [elsif value name =~ /^barb/i] [or value name =~ /^mary/i] This is an elsif with Barb or Mary. [elsif value name =~ /^pat/i] [and value othername =~ /^mike/i] This is an elsif with Pat and Mike. [/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:
[if config CreditCardAuto] Auto credit card validation is enabled. [/if]
[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]
[if discount 99-102] Item is discounted. [/if]
[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]
[if file /home/user/www/images/[item-code].gif] <IMG SRC="[item-code].gif"> [/if]
The file test requires that the SafeUntrap directive contains
ftfile
(which is the default).
[if items]You have items in your shopping cart.[/if] [if items layaway]You have items on layaway.[/if]
[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.)
[if salestax [value state] > 0] There is salestax for your state. [else] No salestax for your state. [/else] [/if]
Key matching is case-insensitive.
[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]
[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.
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]
.
[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 interpolation.
[elsif type="type" term="field" op="op" compare="compare"]
Additional conditions for test, applied if the initial [if ..]
test fails.
[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.
Many MiniVend functions can be controlled or specified with [tag ...][/tag]
pairs.
Named syntax:
[tag op=operation arg="arg1 arg2 ..."]other[/tag]
[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]
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
.
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).
[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
.
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]<CODE></CODE>, [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/report.html for an
example.
[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]
&
#lt; and &
#91; respectively.
[tag show_tags][value whatever][/tag]
[tag time]%A, %B %d, %Y[/tag]
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]
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, defined in minivend.cfg
.
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 -- in fact, you can override the base MiniVend tag set with them. 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 can 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
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:
undef
, interpolate
, and any other attributes you have set in the tag. Allows your tag routine
to take a hash reference with the important parameters. Example:
UserTag echo-params AddAttr UserTag echo-params Routine <<EOR sub { my($ref) = @_; my $out; for (sort keys %$ref) { # skip these meaningless parameters next if /^(undef|true|false)$/;
$out .= "$_="; $out .= '"'; $out .= $ref->{$_}; $out .= '"' $out .= "\n"; } return $out; } EOR
If you define the above UserTag and put put this on a MiniVend page
<PRE> [echo-params Param1=1 param2=2 param3=three] </PRE>
the resulting output will be:
interpolate="0" param1="1" param2="2" param3="three"
The interpolate
parameter is always present for every tag, and defines the behavior of
container text or output depending on the value of HasEndTag.
UserTag tagname Alias tag to insert
An Alias is the only property that does not require a Routine to process the tag.
UserTag tagname attrAlias alias attr
As an example, the standard MiniVend value tag takes a named attribute of name for the variable name, meaning that [value name=var]
will display the value of form field var
. If you put this line in catalog.cfg:
UserTag value attrAlias identifier name
then [value identifier=var]
will be an equivalent tag.
tag_loop_list
and tag_if
in lib/Vend/Interpolate.pm for an example of a nesting tag.
UserTag tagname CanNest
[/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
attribute
instead of an attribute=value
pair. It must be a recognized attribute in the tag definition, or there
will be big problems. Use this with caution!
UserTag tagname Implicit attribute value
If you want to set a standard include file to a fixed value by default, but
don't want to have to specify [include file="/long/path/to/file"]
every time, you can just put:
UserTag include Implicit file file=/long/path/to/file
and [include file]
will be the equivalent. You can still specify another value with [include file="/another/path/to/file"]
UserTag tagname InsertHTML htmltag mvtag|mvtag2|mvtagN
In MiniVend's standard tags, among others, the <
OPTION ...> tag has the
[selected ..]
and [checked ...]
tags included with them, so that you can do:
<INPUT TYPE=checkbox MV="checked mvshipmode upsg" NAME=mv_shipmode> UPS Ground shipping
to expand to this:
<INPUT TYPE=checkbox CHECKED NAME=mv_shipmode> UPS Ground shipping
Providing, of course, that mv_shipmode
is equal to upsg. If you want to turn off this behavior on a per-tag basis, add the
attribute mv.noinsert=1 to the tag on your page.
UserTag tagname InsideHTML htmltag mvtag|mvtag2|mvtagN
In MiniVend's standard tags, the only InsideHTML tag is the < SELECT> tag when used with loop, which causes this:
<SELECT MV="loop upsg upsb upsr" NAME=mv_shipmode> <OPTION VALUE="[loop-code]"> [shipping-desc [loop-code]] </SELECT>
to expand to this:
<SELECT NAME=mv_shipmode> [loop upsg upsb upsr] <OPTION VALUE="[loop-code]"> [shipping-desc [loop-code]] [/loop] </SELECT>
Without the InsideHTML setting, the [loop ...]
would have been outside
of the select -- not what you want. If you want to turn off this behavior
on a per-tag basis, add the attribute mv.noinside=1 to the tag on your
page.
UserTag
will be re-parsed for more MiniVend tags. If it is a container, Interpolate
causes the contents of the tag to be parsed before the tag routine is run.
UserTag tagname Interpolate
UserTag tagname InvalidateCache
It does not override [tag flag build][/tag]
, though.
UserTag tagname Order param1 param2
[usertag argument]
instead of [usertag ARG=argument]
. If not defined, Routine is used, and MiniVend will usually do the right thing.
UserTag tagname ReplaceAttr htmltag attr
An example is the standard
HTML <
A
HREF=...> tag. If you want to use the MiniVend tag
[area pagename]
inside of it, then you would normally want to replace the
HREF attribute. So the equivalent to the following is
defined within MiniVend:
UserTag area ReplaceAttr a href
Causing this
<A MV="area pagename" HREF="a_test_page.html">
to become
<A HREF="http://yourserver/cgi/simple/pagename?X8sl2lly;;44"> when intepreted. =item ReplaceHTML
For HTML-style tag use only. Causes the tag containing the MiniVend tag to be stripped and the result of the tag to be inserted, for certain tags. For example:
UserTag company_name Routine sub { my $l = shift; return "$l: XYZ Company" } UserTag company_name HasEndTag UserTag company_name ReplaceHTML b company_name
<BR> is the HTML tag, and ``company_name'' is the MiniVend tag. At that point, the usage:
<B MV="company-name"> Company </B> --->> Company: XYZ Company
Tags not in the list will not be stripped:
<I MV="company-name"> Company </I> --->> <I>Company: XYZ Company</I>
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
code="code"
quantity="N"
base="database"
noformat=1*
optionX="value"]
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. To receive a raw number,
with no currency formatting, use the option noformat=1
.
As of MiniVend 3.15, if an named attribute corresponding to a product option is passed, and that option would cause a change in the price, the appropriate price will be displayed.
DEMO
EXAMPLE: The T-Shirt (product code 99-102), with a base price of $10.00, can vary in price depending on size and color.
S
, the small size, is 50 cents less; XL
, the extra large size, is $1.00 more, and the color RED
is 0.75 extra. There are also quantity pricing breaks (see the demo pricing database. So the following will be true:
[price code=99-102 size=L] is $10.00 [price code=99-102 size=XL] is $11.00 [price code=99-102 color=RED size=XL] is $11.75 [price code=99-102 size=XL quantity=10] is $10.00 [price code=99-102 size=S] is $9.50
An illustration of this is on the flypage template when passed that item code.
[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="code"
arg="attribute*, type*, field*, database*, name*, outboard*"]
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.
See Item Attributes for a complete description of the arguments.
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.
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.
positional: [file 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.
The optional type parameter will do an appropriate ASCII translation on the file before it is sent.
[include file="name"]
NOTE: New to MiniVend 3.04.
Same as [file name]
except interpolates for all MiniVend tags and variables.
Tags to help manage page appearance and advertising links:
[body type="n" extra="ATTRIBUTE"]
Selects from the predefined color schemes and/or backgrounds, and just
becomes a <
BODY> tag if none are defined. The extra
parameter is always appended. See CONTROLLING PAGE APPEARANCE.
[buttonbar type="n"]
Selects from the predefined buttonbars, and is stripped if it doesn't exist. See CONTROLLING PAGE APPEARANCE.
positional: [rotate ceiling* floor*]
AUTOINTERPOLATE: Yes, can be turned off with INTERPOLATE=0
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, and each floor/ceiling
combination has a separate rotation value.
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 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]
tag.
[shipping-description name="mode"]
The text description of mode -- the default is the shipping mode currently selected.
[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.
[calc] 2 + 2 [/calc]
will display:
4
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.
TIP: The [calc]
tag will remember variable values inside one page, so you can do the
equivalent of a memory store and memory recall for a loop.
[currency convert=1*]
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 and PriceCommas settings as appropriate, and can contain a [calc]
region. If the optional ``convert'' parameter is set, it will convert
according to PriceDivide> for the current locale. If Locale is set to fr_FR
, and PriceDivide for fr_FR
is 0.167, the following sequence
[currency convert=1] [calc] 500.00 + 1000.00 [/calc] [/currency]
will cause the number 8.982,04 to be displayed.
[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 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 nn]
element.
[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.
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.
NOTE: The special tags that reference item within the list are not normal MiniVend tags, do not take named attributes, and cannot be contained in an HTML tag (other than to substitute for one of its values or provide a conditional container). They are interpreted only inside their corresponding list container. Normal MiniVend tags can be interspersed, though they will be interpreted after all of the list-specific tags.
Between the item_list markers the following elements will return information for the current item:
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.
NOTE: This tag does not nest with other [if-data ...]
tags.
[if-data]
.
[if_data table column]
element.
[/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.
NOTE: This tag does not nest with other [if-field ...]
tags.
[if-field]
.
[if_field fieldname]
element.
[else]NOT DIVISIBLE TEXT[/else]
is present, then the
NOT
DIVISIBLE
TEXT will be displayed.
For example:
[item-alternate 2]EVEN[else]ODD[/else][/item-alternate] [item-alternate 3]BY 3[else]NOT by 3[/else][/item-alternate]
ProductFiles
, in that order, for the data, returning the value only if that key is
defined. In most catalogs, where ProductFiles
is not defined (i.e. the demo), [item-field title]
is equivalent to
[item-data products title]
.
Evaluates to the field name fieldname in the products database, for the current item. If the item is not found in the first of the ProductFiles, all will be searched in sequence.
[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.)
NOTE: no
HTML style.
attribute
for the current item.
[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.)
n
(from the products file) of the current item, with currency formatting. If
the optional ``noformat'' is set, then currency formatting will not be
applied.
n
(from the products file) of the current item, with currency formatting. If
the optional ``noformat'' is set, then currency formatting will not be
applied. Returns regular price if not discounted.
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.
named attributes: [perl arg="arguments"* interpolate=1*]
HTML example:
<PRE mv=perl mv.arg="values browser"> $name = $Safe{'values'}{'name'}; $name = $Safe{'browser'}; return "Hi, $name! How do you like your $browser? </PRE>
IMPORTANT NOTE: The [perl]
tag enforces Safe.pm checking, and many standard Perl operators are not available. This is a good
thing, as you would not want users having access to all files and programs
on the system with the MiniVend daemon's permissions! See GlobalSub
and UserTag for ways to make external files and programs available to MiniVend.
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:
# New syntax # If the item might contain a single quote [perl interpolate=1] $comments = '[value comments escaped]'; [/perl]
# Simple example, old syntax [compat][perl] $comments = '[value comments]'; [/perl][/compat]
# 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]);
The arguments that can be passed are any to all of:
# 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.
# Set if the user had a value for name in the *current* form $name = $Safe{'cgi'}->{name};
[[any]]
and [post]
modifiers). The file name is relative to the MiniVend base directory unless
specified as an absolute path.
[frames-off]
or
[frames-on]
. Referred to in your code as $Safe{frames}.
# 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};
@_
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 pre-compiled. (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.
# 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 arg=browser] my $html = '<H5>'; $html .= $Safe{'browser'}; $html .= '</H5>'; $html; [/perl]
To show the user their name, and the current time:
[perl arg=values]
my $string = "Hi, " . $Safe{'values'}{'name'} ". The time is now "; $string .= localtime; $string;
[/perl]
MiniVend 3.15 supports an ASP-like syntax using the mvasp
tag.
[mvasp] <HTML><BODY> This is HTML.<BR>
<% HTML "This is code<BR>"; %> More HTML.<BR> <% $Document->write("Code again.<BR>") %> [/mvasp]
If no closing [/mvasp]
tag is present, the remainder of the page will be seen as
ASP.
ASP is simple. Anything between <% and %> is code, and the string %> is not allowed anywhere inside. Anything not between those anchors is plain HTML that will be placed unchanged on the page. MiniVend variables and [L][/L] and [LC][/LC] areas will still be inserted, but any MiniVend tags will not be.
There is a shorthand <% = $foo
%>, which is exactly equivalent to <% $Document->write($foo); %> or <%
HTML $foo; %>
[mvasp] <HTML><BODY> This is HTML.<BR> [value name] will show up as [value name].<BR>
__VARIABLE__ value is equal to: __VARIABLE__
<% = "This is code<BR>" %>
The
__VARIABLE__ will be replaced by the value of Variable VARIABLE
, but [value name] will be shown unchanged.
There is a complete object structure for use by the ASP:
%CGI::values
, the value of user variables as submitted in the current page/form. To get
the value of a variable submitted as
<INPUT TYPE=hidden NAME=foo VALUE=bar>
use
<% $Document->write("Value of foo is $CGI->{'foo'}"); %>
HTML $foo; # Append $foo to the write buffer array $Document->write($foo); # object call to append $foo to the write # buffer array $Document->insert($foo); # Insert $foo to front of write buffer array $Document->header($foo, $opt); # Append $foo to page header $Document->send(); # Send write buffer array to output, done # automatically upon end of ASP, clears buffer # and invalidates $Document->header() $Document->hot(1); # Cause writes to send immediately $Document->hot(0); # Stop immediate send @ary = $Document->review(); # Place contents of write buffer in @ary $Document->replace(@ary) # Replace contents of write buffer with @ary $ary_ref = $Document->ref(); # Return ref to output buffer
$foo
to the page in a buffered fashion. The buffer is an
array that is the results of all previous $Document-
>write()
operations. If $Document->hot(1) has been set, the output immediately
goes to the user.
$foo
to the page buffer.
$Document->write("23"); $Document->insert("1"); $Document->send();
will output ``123'', while
$Document->write("23"); $Document->write("1"); $Document->send();
will output ``231''.
$foo
to the
HTTP header. You can use this to change the page
content type, cache options, or other attributes.
The below code changes the content type (MIME type) to text/plain:
$Document->header("Content-type: text/plain");
There is an option hash that can be sent, with the only valid value being ``replace''. The below code scrubs all previous header lines:
$Document->header("Content-type: text/plain", { replace => 1 } );
Once you have sent output with $Document->send(), this can no longer be done.
$foo
is true (in a Perl sense), then all
$Document->write() operations will be immediately sent until a
$Document->hot(0) is executed.
Can be used to implement non-parsed-header operation.
@ary = $Document->review();
# Remove the first item in the write buffer my $ary_ref = $Document->ref(); shift @$ary_ref;
Shopping carts are an array of hash references. Here is an example of a
session cart array containing a main
and a layaway
cart.
{ 'main' => [ { 'code' => '00-0011', 'mv_ib' => 'products', 'quantity' => 1, 'size' => undef, 'color' => undef }, { 'code' => '99-102', 'mv_ib' => 'products', 'quantity' => 2, 'size' => 'L', 'color' => 'BLUE' } ], 'layaway' => [ { 'code' => '00-341', 'mv_ib' => 'products', 'quantity' => 1, 'size' => undef, 'color' => undef } ] }
In this cart array $Carts->{main}[1]{'code'} is equal to 99-102
. In the normal course of events, it would be equivalent to
$Items->[1]{'code'}.
# Turn off CyberCash for this user $Config->{CyberCash} = 0;
Changes are not persistent except when running in the foreground (Debug mode or on Windows).
HTML $foo, $bar;
is exactly equivalent to
$Document->write($foo, $bar);
Honors the $Document->hot() setting.
[cart ...]
tag, it is normally the same as $Carts->{main}.
[scratch foo]
.
<% $Scratch->{foo} = 'bar'; %>
is equivalent to:
[set foo]bar[/set]
[data session username]
.
<% my $out = $Session->{browser}; $Document->write($out); %>
is equivalent to:
[data session browser]
You can also set values. If you wanted to change the value of
[data session source]
, for example, you could do:
<% $Session->{source} = 'New_partner'; %>
$Tag
object, you can access any MiniVend tag
including user-defined tags.
IMPORTANT NOTE: If the tag will access a database that has not been previously opened, you must pass in the table name in the ASP call, i.e.:
# HTML style <HTML MV="mvasp" MV.TABLES="products pricing"> or # Named parameters [mvasp tables="products pricing"] or # Positional parameters [mvasp products pricing]
Any tag can be called.
<% my $user = $Session->{username}; my $name_from_db = $Tag->data('userdb', 'name', $user ); $Document->write($name_from_db); %>
is the same as:
[data table=userdb column=name key="[data session username]"]
If the tag has a dash (-
) in it, use an underscore instead:
# WRONG!!! $Tag->shipping-desc('upsg'); # Right $Tag->shipping_desc('upsg');
There are two ways of specifying parameters. You can either use the positional parameters as documented (for an authoritative look at the parameters, trace the %Routine value in Vend::Parse), or you can specify it all with an option hash parameter names as in any named parameters as you would specify in a MiniVend tag. The calls
$Tag->data('products', 'title', '00-0011');
and
my $opt = { table => 'products', column => 'title', key => '00-0011', };
$Tag->data( $opt );
are equivalent for the data tag.
If you are using the option hash method, and the tag has container text,
you can either specify it in the hash parameter body
or add it as the next argument. The two calls:
$Tag->item_list( { 'body' => "[item-code] [item-field title]", });
and
$Tag->item_list( { }, "[item-code] [item-field title]")
are equivalent.
Parameter names are ALWAYS lower case.
[value foo]
.
<% $Document->write($Values->{foo}); %>
is equivalent to:
[value foo]
<% Log("error log entry"); %>
It prepends the normal timestamp with user and page information. To supress
that information, begin the message with a backslash (\
).
<% Log("\\error log entry without timestamp"); Log('\another error log entry without timestamp'); Log("error log entry with timestamp"); %>
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 arg="item item"]
tag is still usable. If you want to have an on-the-fly page mixed in, use
the [fly-list CODE BASE]
[/flylist]
pair, which essentially encapsulates a flypage within a page.
Defines an area in a random page which performs the flypage lookup function, implementing the tags below.
[fly-list code="[data session arg]"] (contents of flypage.html) [/fly-list]
If you place the above around the contents of the demo flypage, in a file
named flypage2.html
, it will make these two calls display identical pages:
[page 00-0011] One way to display the Mona Lisa [/page] [page flypage2 00-0011] Another way to display the Mona Lisa [/page]
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>
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.
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.
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]
region.
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:
[finish_order]
tag.
[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.
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.
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.
MiniVend as of 3.12 supports file upload with the multipart/form-data
type. The file is placed in memory and discarded if not accessed with the [value-extended name=filevar file_contents=1]
tag or written with [value-extended name=filevar outfile=your_file_name]
. See
Extended Value Access and File Upload.
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 scan Type Description
mv_all_chars ac S Turns on punctuation matching mv_arg[0-9]+ A Parameters for mv_subroutine (mv_arg0,mv_arg1,...) mv_base_directory bd S Sets base directory for search file names mv_begin_string bs S Pattern must match beginning of field mv_case cs 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 routine, 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 co S Enables field/spec matching coordination mv_column_op op S Operation for coordinated search mv_credit_card* O Discussed in order security (some are read-only) mv_delay_page dp S Delay search until after inital page display mv_dict_end de S Upper bound for binary search mv_dict_fold df S Non-case sensitive binary search mv_dict_limit di S Sets upper bound based on character position mv_dict_look dl S Search specification for binary search mv_dict_order do 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 em S Sets word-matching mode mv_failpage O,S Sets page to display on failed order check/search mv_field_names fn S Sets field names for search, starting at 1 mv_first_match fm S Start displaying search at specified match mv_head_skip hs S Sets skipping of header line(s) in index mv_index_delim id S Delimter for search fields (TAB default) mv_matchlimit ml S Sets match page size mv_max_matches mm S Sets maximum match return (only for Glimpse) mv_min_string ms S Sets minimum search spec size mv_negate ne S Records NOT matching will be found mv_nextpage A Sets next page user will go to after submission mv_numeric nu S Comparision numeric in coordinated search 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 os S Selects AND/OR of search words mv_profile mp S Selects search profile mv_range_alpha rg S Sets alphanumeric range searching mv_range_look rl S Sets the field to do a range check on mv_range_max rx S Upper bound of range check mv_range_min rm S Lower bound of range check mv_record_delim dr S Search index record delimiter mv_return_all ra S Return all lines found (subject to range search) mv_return_delim rd S Return record delimiter mv_return_fields rf S Fields to return on a search mv_return_file_name rn S Set return of file name for searches mv_return_spec rs S Return the search string as the only result mv_save_session C Set to non-zero to prevent expiration of user session mv_search_field sf S Sets the fields to be searched mv_search_file fi S Sets the file(s) to be searched mv_search_line_return lr S Each line is a return code (loop search) 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 sp S Sets the page for search display mv_searchspec se S Search specification mv_searchtype st S Sets search type (text, glimpse, db or sql) mv_separate_items O Sets separate order lines (one per item ordered) mv_shipmode O Sets shipping mode for custom shipping mv_sort_command tc S Sets the command to use for sorting searches mv_sort_crippled S Sets crippled sort mode mv_sort_field tf S Field(s) to sort on mv_sort_option to S Options for sort mv_spelling_errors er S Number of spelling errors for Glimpse mv_substring_match su 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_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_unique un S Return unique search results only mv_value va S Sets value on one-click search (va=var=value)
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:
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.
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 �
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]
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:
[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>
You can provide a ``memory'' for drop-down menus, radio buttons, and
checkboxes with the [checked]
and [selected]
tags.
This will output
CHECKED if the variable var_name
is equal to
value. Not case sensitive.
As of 3.11: If the multiple
attribute is defined and set to a non-zero value (1 is implicit) then if the value matches on a word/non-word boundary it will be
CHECKED. If the
default
attribute is set to a non-zero value, then the box will be checked if the
variable var_name
is empty or zero.
[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>
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
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.
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.
MiniVend as of 3.12 has a facility for greater control over the display of
form variables; it also can parse multipart/form-data
forms for file upload.
File upload is simple. You define a form like:
<FORM ACTION="[process-target] METHOD=POST ENCTYPE="multipart/form-data"> <INPUT TYPE=hidden NAME=mv_todo VALUE="return"> <INPUT TYPE=hidden NAME=mv_nextpage VALUE="test"> <INPUT TYPE=file NAME=newfile> <INPUT TYPE=hidden NAME=testvar VALUE="value0"> <INPUT TYPE=hidden NAME=testvar VALUE="value1"> <INPUT TYPE=hidden NAME=testvar VALUE="value2"> <INPUT TYPE=submit VALUE="Go!"> </FORM>
The [value-extended ...] tag allows access to all of these things. If you
put on the test.html
page and use with the above form you can see how it is used:
<PRE> testvar element 0: [value-extended name=testvar index=0] testvar element 1: [value-extended name=testvar index=1] testvar elements: joined with a space: |[value-extended name=testvar]| joined with a newline: |[value-extended joiner="\n" name=testvar index="*"]| first two only: |[value-extended name=testvar index="0..1"]| first and last: |[value-extended name=testvar index="0,2"]| Uploaded file name: [value-extended name=newfile] Is newfile a file? [value-extended name=newfile yes=Yes no=No test=isfile] Write the file. [value-extended name=newfile outfile=junk.upload] Write again with indication: [value-extended name=newfile outfile=junk.upload yes="Written."] no=FAILED] And the file contents: [value-extended name=newfile file_contents=1] </PRE>
The syntax for [value-extended ...]
is:
named: [value-extended name=formfield outfile=filename* ascii=1* yes="Yes"* no="No"* joiner="char|string"* test="isfile|length|defined"* index="N|N..N|*" file_contents=1* elements=1*]
positional: [value-extended name]
HTML examples:
No match found for <PARAM MV="value-extended" MV.JOINER=" and " MV.NAME=mv_searchspec> <INPUT TYPE="text" NAME="mv_searchspec" VALUE="[value-extended name=mv_searchspec index=0]"> <INPUT TYPE="text" NAME="mv_searchspec" VALUE="[value-extended name=mv_searchspec index=1]">
Expands into the current value of the customer/form input field named by field. If there are multiple elements of that variable, it will return the value at index; by default all joined together with a space.
If the variable is a file variable coming from a multipart/form-data file upload, then the contents of that upload can be returned to the page or optionally written to the outfile.
In the special case of a file upload, the value returned is the name of the file as passed for upload.
isfile
returns true if the variable is a file upload.
length
returns the length. defined
returns whether the value has ever been set at all on a form.
*
, will return all (joined by joiner). If a range, such as 0 .. 2
, will return multiple elements.
1
for tests and the empty string for uploads.
Any MiniVend database can be updated with a form using the following method.
NOTE: All operations are performed on the database, not the
ASCII source file. You will have to perform a [tag export table_name][/tag]
operation if you want the
ASCII source file to reflect the results of the
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, special MiniVend variables are used to select the database parameters:
The MiniVend action set 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=hidden NAME="mv_todo" VALUE="set"> <INPUT TYPE=submit VALUE="Update table"> </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.
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 link-based searches that are called with the special page name
scan
. The search engine uses many special MiniVend tags and variables.
If the search is implemented in a link or a form, it will always display
formatted results on the results page, a MiniVend page that uses some combination of the [search-region]
, [search-list]
,
[more-list]
, [more]
, and other MiniVend tags to format and display the results. The search
results are usually a series of product codes/SKUs or other database keys,
which are then iterated over similar to the
[item-list]
.
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.)
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).
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 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 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.
The search must be done on a dictionary-ordered pre-built index, which can be produced with the database INDEX modifier. See Dictionary indexing with INDEX.
If you use the mv_dict_look parameter by itself, and the proper index file is present, MiniVend should set the options:
mv_return_fields=1 mv_dict_limit=-1
This will make the search behave much like the simple search described above, except it will be much faster on large files and will match only from the beginning of the field.
MiniVend will do a complete range of tests on individual columns in the database. To use this function, set mv_coordinate to yes (co=yes in the one-click syntax).
In order to use coordinated searching, the number of search fields must equal the number of search strings. This makes sense if you think about it a bit.
If you want to make sure that is the case, use the mv_search_map
variable. It allows you to map variables to others in the search
specification. For example:
<INPUT TYPE=hidden NAME=mv_search_map VALUE=" mv_searchspec=search1 mv_searchspec=search2 mv_searchspec=search3 "> <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=category> Artist: <INPUT NAME=search1 VALUE="[value search1]"> Title: <INPUT NAME=search2 VALUE="[value search2]"> Genre: <INPUT NAME=search3 VALUE="[value search3]">
Even if the user leaves one blank, the search will work.
Leading/trailing whitespace is stripped from all lines in the mv_search_map variable, so you can position it as shown for convenience.
Coordinated searches may be joined with the output of another table if you
set one of the mv_search_field values to a table:column
pair. Note that this will slow down large searches considerably unless you
have another search specification, as the database must be accessed for
every search line! If you have a search field that qualifies for a regular
expression search function, or are doing a binary search with
mv_dict_look, or are not doing an OR
search, the penalty should not be too great as only matching lines will
cause an access to the database.
Individual field operations can then be specified with the mv_column_op
(or op) parameter. The operations include:
operation string numeric equivalent --------- equal to eq == = not equal ne != <> greater than gt > less than lt < less than/equal to le <= greater than/equal to ge >= regular expression rm =~ , LIKE regular expression NOT rn !~ exact match em
An example:
[page scan co=yes sf=title se=Sunflowers op=em sf=artist se=Van Gogh op=rm ] Sunflowers, Van Gogh [/page]
[page scan co=yes sf=title se=Sunflowers nu=0 op=!~ sf=artist se=Van Gogh op=rm nu=0
sf=inventory:qty se=1 op=>= nu=1 ] Any in stock except Sunflowers, Van Gogh [/page]
The second search will check the stock status of the painting provided
there is an inventory
table as in some of the MiniVend demo catalogs. If the qty
field is greater than or equal to 1, then the product will be picked. If
out of stock, it will not be found.
It always helps to have an rm
type included in the search. This is used to pre-screen records so that
database accesses only need be made for already-matching entries. If
accesses must be made for every record large searches can get quite slow.
If you have installed Jochen Wiedmann's SQL::Statement
module, you can specify an
SQL syntax for the text-based search. (This is not the same as the the
SQL search, treated below separately. It would work on an
SQL table but only on the
ASCII text source file, not on the actual database.)
This syntax allows this rather nice form setup:
Artist: <INPUT NAME="artist"> Title: <INPUT NAME="title"> <INPUT TYPE=hidden NAME="mv_sql_query" VALUE=" SELECT code FROM products WHERE artist LIKE artist AND title LIKE title">
If the right hand side of an expression looks like a column, i.e. is not quoted, then the appropriate form variable is substituted. (If used in a one-click, the corresponding scratch variable is used instead.) The assumption is reversed for the left-hand side -- if it is a quoted string then the column name is read from the passed values -- otherwise the column name is literal.
Search for: <INPUT NAME="searchstring"><BR> Search in <INPUT TYPE="radio" NAME="column" VALUE="title"> title <INPUT TYPE="radio" NAME="column" VALUE="artist"> artist <INPUT TYPE=hidden NAME="mv_sql_query" VALUE="SELECT code FROM products WHERE 'column' LIKE searchstring">
Once again, this does not do a search on an SQL database, but formats a corresponding text-based search. Parentheses will have no effect, and an OR condition will cause all conditions to be OR. The searches above would be similar to:
[page href=scan arg=" co=yes sf=artist op=rm se=[value artist] sf=title op=rm se=[value title] " ] Search for [value artist], [value title] [/page] [page href=scan arg=" co=yes sf=[value column] op=rm se=[value searchstring] " ] Search for [value searchstring] in [value column] [/page]
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.
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_delay_page S Sets the page for delayed search display 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, db, 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:
<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> Surrealists </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.
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 search specs 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
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 MM mv_more_matches ne mv_negate SE mv_raw_searchspec nu mv_numeric ac mv_all_chars op mv_column_op bd mv_base_directory os mv_orsearch bs mv_begin_string ra mv_return_all co mv_coordinate rd mv_return_delim cs mv_case rf mv_return_fields de mv_dict_end rg mv_range_alpha df mv_dict_fold rl mv_range_look di mv_dict_limit rm mv_range_min dl mv_dict_look rn mv_return_file_name do mv_dict_order rs mv_return_spec dp mv_delay_page rx mv_range_max dr mv_record_delim se mv_searchspec em mv_exact_match sf mv_search_field er mv_spelling_errors sp mv_search_page fi mv_search_file sq mv_sql_query fm mv_first_match st mv_searchtype fn mv_field_names su mv_substring_match hs mv_head_skip tc mv_sort_command id mv_index_delim tf mv_sort_field lr mv_search_line_return to mv_sort_option ml mv_matchlimit ty mv_sort_crippled mm mv_max_matches un mv_unique mp mv_profile va mv_value
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  
will not be recognized. If you use one of the methods below to escape these
``unsafe'' characters, you won't have to worry about this.
IMPORTANT NOTE: An incompatibility in earlier MiniVend catalogs is specifying [page scan/se=searchstring]
on a [new]
parsed page. This is interpreted by the new parser as [page scan/se="searchstring"]
and will cause a bad
URL. Change this to [page scan se=searchstring]
to make those earlier catalogs work with MiniVend 3.10 and higher.
Beginning in MiniVend 3.08, you may specify a one-click search in three different ways. The first is as used in previous versions, with the scan
URL being specified completely as the page name; this will only work in a
[compat] [/compat]
region or on an [old]
page. The second two use the ``argument'' parameter to the [page ...]
or [area ...]
tags to specify the search (an argument to a scan is never valid anyway).
[page scan se=Surreal/se=Gogh/os=yes/su=yes/sf=artist/sf=category] Van Gogh -- compare to surrealists [/page]
In this method of specification, 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.)
[page scan se="Van Gogh" sp=lists/surreal os=yes su=yes sf=artist sf=category ] Van Gogh -- compare to surrealists [/page]
Any ``unsafe'' characters will be escaped. If you need to search for trailing spaces (unlikely) you must quote.
[page scan se="Van Gogh"&sp=lists/surreal&os=yes&su=yes&sf=artist&sf=category] Van Gogh -- compare to surrealists [/page]
Any ``unsafe'' characters will be escaped.
New syntax and old syntax handle the tags the same, though if by some odd
chance you wanted to be able to search for a ]
(right square bracket) you would need to use new syntax.
As of MiniVend 3.11, you can specify a value that will be set in the link
with the mv_value parameter. It takes an argument of var=value
, just as you would set a normal variable in a MiniVend profile. Actually
mv_value is a misnomer, for you would almost never use it in a form, where you can
easily set variable values. You will always specify it in a one-click
search with va=var=value
. Example:
[page href=scan arg="se=Renaissance se=Impressionists va=category_name=Renaissance and Impressionist Paintings os=yes"]Renaissance and Impressionist Paintings[/page]
Now you can display the appropriate category on the search results page
with [value category_name]
.
NOTE: This section is appropriate for MiniVend 3.09 and above.
You may specify a search inside a page with the [search parameters*]
or
[search_region parameters*]
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 [loop ...]
tag directly accepts a search parameter. To search for all products in the
categories ``Americana'' and ``Contemporary'' you can do:
[loop search=" se=Americana se=Contemporary os=yes sf=category9 "] 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.
The syntax is a bit tricky because of the
HTML style evaluation and the =
signs in both argument types, so you may want to pre-set the search
arguments with a search profile. Any string passed to the search tag that
doesn't contain an equals (=
) sign is considered a search profile name. Example:
[set My search] mv_searchspec=Americana mv_searchspec=Contemporary mv_search_field=category mv_orsearch=yes [/set]
Now doing a search with [search My search]
or [loop search="My search"]
will use the above settings.
If you want to use the shorthand ``se=Americana'' notation, you can set the special scratch variable mv_search_arg:
[set mv_search_arg] se=Americana se=Contemporary sf=category os=yes [/set]
A search with empty parameters, as in [search] or [loop search=""]
, will yield the same results. (You must define an empty string with quote
marks for the second notation -- [loop search=]
will not work.)
To place an in page search with the full range of display in a normal
results page, use the [search-region]
tag the same as above, except that you can place [search-list]
, [more-list]
, and [more]
tags within it and use them to display and format the results -- including
paging.
For example:
[search-region se=Americana sf=category ml=2 ] [more-list][more][/more-list] [search-list] <A MV="page [item-code]" HREF="flypage.html"> [item-field title]<A>, by [item-field artist] [/search-list] [no-match] Sorry, no matches for [value mv_searchspec]. [/no-match] [/search-region]
If you want to use the same page for search paging, make sure you set the sp=page
parameter.
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_search_field=artist mv_search_field=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_search_field=artist mv_search_field=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.
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
.
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.
Set this if you anticipate searching for lots of punctuation characters that might be special characters for Perl -- the characters ()[]\$^ are included.
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.
If you use an absolute path directory, for security you must enable it in the users session with:
[set /directory/name]1[/set]
This prevents users from setting an arbitrary value and viewing arbitrary files.
This is a multiple parameter. If mv_coordinate is in force, then it should be set as many times as necessary to match the field/searchstring combination. If set only once, it applies to all fields. If set more than once but not as many times as the fields, it will default to off.
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.
Case sensitivity, substring matching, and negation all work on a field-by field basis according to the following:
If a search specification is blank, it will be removed and all case-sensitivity/negation/substring options will be adjusted accordingly.
The order of this and the mv_dict_end variable is significant -- each will overwrite the other.
If this is set to a non-numeric value, an automatic mode is entered which
looks for a dictionary-indexed file that corresponds to the file name plus
.field, where field is what you have set mv_dict_limit to. The actual value of mv_dict_limit is set to -1
. If the file does not exist, then the original file is silently used (this
might not be what you want!). Also, the value of mv_return_fields is set to 1
to correspond to the location of the key in the auto-indexed file.
To illustrate:
<INPUT TYPE=hidden NAME=mv_dict_limit VALUE=category> <INPUT TYPE=hidden NAME=mv_search_file VALUE="products.asc">
is equal to:
<INPUT TYPE=hidden NAME=mv_dict_limit VALUE="-1"> <INPUT TYPE=hidden NAME=mv_search_file VALUE="products.asc.category"> <INPUT TYPE=hidden NAME=mv_return_fields VALUE="1">
The real utility would be in a form construct like
Search for <SELECT NAME=mv_dict_limit> <OPTION> author <OPTION> title </SELECT> beginning with <INPUT NAME=mv_dictlook>
which would allow automatic binary search file selection.
Combined with the INDEX
attribute to the Database directive, this allows fast binary search qualification combined with
regular
mv_searchspec text searches.
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]
.
[more-list]
is present. Can be implemented as a scrolling list
(INPUT
TYPE=SELECT) or radiobox
(INPUT
TYPE=RADIO) 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_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.
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).
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.
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).
If set to sql, formulates an SQL select statement to return the search list.
If set to db, iterates over every row of the database (not the associated text source file).
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.
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.
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.
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.
Once a search has been done, there needs to be a way of presenting the
output. By default, the SpecialPage search is used -- it is set to results
in the distribution demo -- 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 the first field returned from the search.
The set of tags for [item-list]
are available, with the exception of tags like [item-modifier]
, [modifier-name]
, [item-accessories]
, and others that access shopping-cart specific elements. Thse include:
[if-data table column] [/if-data] [if-field column] [/if-field] [item-code] [item-data table column] [item-discount] [item-field column] [item-price quantity* noformat*]
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.
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] <B>[item-field title]</B>, by [item-field artist]<BR> [/search-list]
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.
[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.
[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] [/else] [/on-change cat] </TD> <TD> [on-change subcat] [condition][item-field subcategory][/condition] [item-field subcategory] [else] [/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
will prevent blanked table cells if you use a border.)
[on-change marker]
.
[more-list]
and [/more-list]
element pair.
[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 friends, 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">
If you wish to set custom text for the ``Previous'' and ``Next'' usually
used, then you can define the next_img, prev_img, and page_img with
[next-anchor][/next-anchor]
, [prev-anchor][/prev-anchor]
and
[page-anchor][/page-anchor]
. The string
$PAGE$ will be replaced with the page number in the
latter. The same example:
[more-list 0 0 0] [next-anchor] Forward [/next-anchor] [prev-anchor] Back [/prev-anchor] [page-anchor] Page $PAGE$ [/page-anchor] [more] [/more-list]
will display U<Forward Page 1 Page 2 Back> for 2 pages.
As shown, you must pass a 0 for the arguments of each to tell MiniVend to look for the assignments.
[more-list]
.
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.
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]
Each catalog may maintain a search cache, which is enabled by specifying
Yes
for the SearchCache directive in catalog.cfg. It operates by developing a
MD5 key or 3-byte checksum of the combined parameters
of a search.
If your catalog frequently specifies category searches in a large catalog, speed of search return can be increased by a large factor, mostly by obviating the need for database lookups.
If you have mostly dynamic session-based content based on user variables, you should not use SearchCache unless you want to give that up. MiniVend will not cache pages with dynamic content, and using cache slows down searches that don't cache.
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, indeed likely in a large catalog, that two separate searches could generate the same 32-bit checksum and return the same cached search.
The search cache is invalidated when a user hits
``RELOAD''. It can also be invalidated by a [set mv_no_cache]1[/set]
scratch setting, which only takes effect for the next page.
If you change your product database or any other files you search, you should reconfigure or the search returns may be wrong. You also may just remove all files in the tmp/ directory.
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.
Multiple page returns are also cached. If you [set mv_no_count]1[/set]
on the calling page, then the user's browser will keep track of the
traveled links.
The last search can be recalled with [page href="[data session last_search]"]
.
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.
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.
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.
If you enable the catalog directive OnFly, setting it to the name of a tag (possibly a UserTag) that can handle its calls, then MiniVend will add items to the basket that are not in the product database.
The OnFly
directive accepts a tag name:
OnFly onfly
MiniVend supplies the onfly
tag which will work with the descriptions below. If your item code is not
to be named mv_order_item
then you must perform a rename in the Autoload
routine.
A basic link can be generated like:
[area form=" mv_todo=refresh mv_order_item=000101 mv_order_fly=description=An on-the-fly item|price=100.01 "]
The form parameter value mv_order_fly
can contain any number of fields which will set corresponding parameters in
the item attributes. The fields are separated by the pipe (|
) character and contain value-parmeter pairs separated by an = sign. (These are URL-encoded by the [area ...] tag, of course.) You can set a size, color, or any other parameter. If you want to see what the actual
URL will look like, put the above example in a page and study it.
The special attribute mv_price
can be used in conjunction with the
CommonAdjust
atom $
to set the price for checkout and display.
The [item-list]
sub-tag [item-description]
, when used with an item-list, will use the item attribute description to display in the basket.
If you wish to set up a UserTag to process on-the-fly items, it should accept a call of
usertag(mv_item_code, mv_item_quantity, mv_order_fly)
The mv_item_code
and mv_order_fly
parameters are required to trigger MiniVend's add_item
routine (along with mv_todo=refresh to set the action).
The item will always act as if SeparateItems
or mv_separate_items
is set.
Multiple items can be ordered at once by stacking the variables. If there
is only one mv_order_item
instance, however, you can stack the mv_order_fly
variable so that all are concatenated together as with the |
symbol. So the above example could be done as:
[area form=" mv_todo=refresh mv_order_item=000101 mv_order_fly=description=An on-the-fly item mv_order_fly=price=100.00 "]
Multiple items would need multiple instances of mv_order_item
with a corresponding mv_order_fly
for each mv_order_item
. You can order both 000101
and 000101
as follows:
[area form=" mv_todo=refresh mv_order_item=000101 mv_order_fly=description=An on-the-fly item|price=100.00 mv_order_item=000102 mv_order_fly=description=Another on-the-fly item|price=200.00 "]
The following two forms correspond to the above two examples, in order, with the slight refinement of adding a quantity:
<FORM ACTION="[area process]" METHOD=POST> <INPUT TYPE=hidden NAME=mv_todo VALUE="refresh"> <INPUT TYPE=hidden NAME=mv_order_item VALUE="000101"> Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1"> <INPUT TYPE=hidden NAME=mv_order_fly VALUE="description=An on-the-fly item|price=100.00"> <INPUT TYPE=submit VALUE="Order button"> </FORM>
<FORM ACTION="[area process]" METHOD=POST> <INPUT TYPE=hidden NAME=mv_todo VALUE="refresh"> <INPUT TYPE=hidden NAME=mv_order_item VALUE="000101"> Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1"><BR> <INPUT TYPE=hidden NAME=mv_order_fly VALUE="description=An on-the-fly item|price=100.00"> <INPUT TYPE=hidden NAME=mv_order_item VALUE="000102"> Qty: <INPUT SIZE=2 NAME=mv_order_quantity VALUE="1"><BR> <INPUT TYPE=hidden NAME=mv_order_fly VALUE="description=Another on-the-fly item|price=200.00"> <INPUT TYPE=submit VALUE="Order two different with a button"> </FORM>
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 sub-item 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.
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:
[order item cart/page] Order it! [/order]
form of order tag to specify an arbitrary order page for an item.
The variables mentioned above modify the page display in the following ways:
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.
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>
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.
As of MiniVend 3.12, you can place a message after the format check requirement.
Specifications take the form of an order page variable (like name or address), followed by an equals sign and one of five check types:
us_postcode
.
Also, there are four pragmas that can be used to change behavior:
&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.
# Success :) &return 1
# Failure :\ &return 0
Will ignore the &fatal
pragma, but &final
is still in effect if set.
As an added measure of control, the specification is evaluated for the
special MiniVend tags to provide conditional setting of order parameters.
With the [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 You must give us your name. address=required Oops! No address. city=required state=required zip=required email=required phone_day=phone_us XXX-XXX-XXXX phone-number for US or Canada &fatal=yes email=email Email address missing the domain? &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.
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.
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>.
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.
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.
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 var]
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.
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.
The simplest method is flat pricing based on a fixed value in the products database. If you put that price in a field named
price
, you don't need to do more. If you want to change pricing based on
quantity, size, color or other factors read on.
As of MiniVend 3.11, a flexible chained pricing scheme is available when the CommonAdjust directive is set.
NOTE: For compatibility with older carts, if both PriceAdjustment and CommonAdjust are set, and CommonAdjust contains a valid database identifier, the CommonAdjust value is used to set pricing adjustments based on item attributes. This is not discussed further in this section; all items below assume PriceAdjustment is not in use.
We talk below about a CommonAdjust string; it will be defined in due time.
A few rules about CommonAdjust, all assuming the PriceField directive is set to price
:
CommonAdjust
is set to any value, a valid CommonAdjust string or not, extended price adjustments are enabled. It may also hold the
default pricing scheme.
price
field may also hold a CommonAdjust string. It takes precedence over the default.
CommonAdjust
directive is set to a CommonAdjust string, and the price
field is empty or specifically 0, then it will be used to set the price of the items.
CommonAdjust
, though it may also contain a CommonAdjust string.
Prices may be adjusted in several ways, and the individual actions are referred to below as atoms. Price atoms they may be final, chained, or fallback. A final price atom is always applied if it does not evaluate to zero. A chained price atom is subject to further adjustment. A fallback price atom is skipped if a previous chained price was not zero.
Atoms are separated by whitespace, and may be quoted (although there should not normally be whitespace in a setting). A chained item ends with a comma. A fallback item has a leading semi-colon. Final atoms have no comma appended or semi-colon prepended.
A settor is the means by which the price is set. There are There are eight different types of price settors. All settors can then yield another CommonAdjust string.
It is quite possible to create endless loops, so the maximum number of initial CommonAdjust strings is set to 16, and there may be only 20 iterations before the price will return zero on an error.
NOTE: Common needs are easily shown but not so easily explained; skip to the examples if the reference below if your vision starts to blur when reading the next section. 8-)
USAGE: Optional items below have asterisks appended. The asterisk should not be used in the actual string. Optional base or table always defaults to the active products database table. The optional key defaults to the item code except in a special case for the attribute-based lookup. The field name is not optional except in the case of an attribute lookup.
pricing:p1,p2,p3,p4,p5,p10:
is the same as
pricing:p1..p5,p10:
Leading non-digits are stripped, and the item quantity is compared with the numerical portion of the column name. The price is set to the value of the database column (numeric portion) that is at least equal to it but doesn't yet reach the next break.
WARNING: If the field at the appropriate quantity level is blank, a zero cost will be returned from the atom. It is important to have all columns populated.
&
sign is stripped and the code is passed to the equivalent of a [calc]
tag. No MiniVend tags can be used, but the &tag_data
routine is available, the current value of the price and quantity are
available as $s, and the current item (code, quantity, price, and any attributes) are
available as $item
, all forced to the package Vend::Interpolate. That means that in a
UserTag:
$Vend::Interpolate::item is the current item $Vend::Interpolate::item->{code} gives key for current item $Vend::Interpolate::item->{size} gives size for current item (if there) $Vend::Interpolate::item->{mv_ib} gives database ordered from
[
) or underscore, it is parsed for MiniVend tags with variable substitution
(but no Locale substitution). You may define a price in a Variable in this fashion. The string is re-submitted as an atom, so it may yield yet
another settor.
mv_price
attribute of the shopping cart, and apply that price as the final price, if
it exists. The attribute must be a numerical value.
$
) the word
will be substituted; i.e. table:column:$
becomes table:column:word
.
settor
will be used as a key for the next lookup, as above.
Most examples below use an outboard database table named pricing, but any valid table including the products table can be used. We will refer to this pricing table:
code common q1 q5 q10 XL S red 99-102 10 9 8 1 -0.50 0.75 00-343 2 red 0.75
The simplest case is a straight lookup on an attribute; size in this case.
10.00, ==size:pricing
With this value in the price
field, a base price of 10.00 will be adjusted with the value of the size attribute. If size for the item 99-102 is set to XL
then 1.00 will be added for a total price of 11.00; if it is S
then .50 will be subtracted for a total price of 9.50; for any other value
of size no further adjustment would be made. 00-343 would be adjusted up 2.00 only
for XL.
10.00, ==size:pricing, ==color:pricing
This is the same as above, except both size and color are adjusted for. A color value of red for item code 99-102 would add 0.75 to the price. For 00-343 it would have no effect.
10.00, ==size:pricing, ==color:pricing:common
Here price is set based on a common column, keyed by the value of the color attribute. Any item with a color value of red would have 0.75 added to the base price.
pricing:q1,q5,q10:, ;10.00, ==size:pricing, ==color:pricing:common
Here is a quantity price lookup, with a fallback price setting. If there is a valid price found at the quantity of 1, 5, or 10, depending on item quantity, then it will be used. The fallback of 10.00 only applies if no non-zero/non-blank price was found at the quantity lookup. In either case, size/color adjustment is applied.
pricing:q1,q5,q10:, ;10.00 ==size:pricing, ==color:pricing:common
Removing the comma from the end of the fallback string stops color/size lookup if it reaches that point. If a quantity price was found, then size and color are chained.
pricing:q1,q5,q10:, ;products:list_price, ==size:pricing, ==color:pricing
The value of the database column list_price
is used as a fallback instead of the fixed 10.00 value. The above value
might be a nice one to use as the default for a typical retail catalog that
has items with colors and sizes.
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
NOTE: PriceAdjustment is slightly deprecated by CommonAdjust, but will remain in use at least through the end of Version 3 of MiniVend.
Configurable directives and tags with regard to pricing:
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.
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.
Numbers that begin with an equals sign (=
) are used as absolute prices and are interpolated for MiniVend tags first, so you can use subroutines to set the price. To facilite coordination
with the subroutine, the session variables item_code
and item_quantity
are set to the code and quantity of the item being evaluated. They would be
accessed in a global subroutine with $Vend::Session-
>{item_code}
and $Vend::Session-
>{item_quantity}
.
The pricing information must always come from a database because of security.
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 ordered.
IMPORTANT NOTE: You may not use the following names for attributes:
item group quantity code mv_ib mv_mi mv_si
You can also set it in scratch with the mv_UseModifier scratch variable -- [set mv_UseModifier]size color[/set]
has the same effect as above. This allows multiple options to be set for
products. Whichever one is in effect at order time will be used. Be
careful, you cannot set it more than once on the same page. Setting the mv_separate_items
or global directive SeparateItems
places each ordered item on a separate line, simplifying attribute
handling. The scratch setting for mv_separate_items
has the same effect.
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 arg="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 <code
size]> or [item-accessories size]
tags are called. They have the syntax:
[item_accessories attribute*, type*, field*, database*, name*, outboard*] [accessories code attribute*, type*, field*, database*, name*, outboard*]
The item attribute as specified in the UseModifier configuration directive.
Typical are size or color
.
select Builds a dropdown <SELECT> menu for the attribute. NOTE: This is the default. multiple Builds a multiple dropdown <SELECT> menu for the attribute. The size is equal to the number of option choices. display Shows the label text for *only the selected option*. show Shows the option choices (no labels) for the option. radio Builds a radio box group for the item, with spaces separating the elements. radio nbsp Builds a radio box group for the item, with separating the elements. radio left n Builds a radio box group for the item, inside a table, with the checkbox on the left side. If "n" is present and is a digit from 2 to 9, it will align the options in that many columns. radio right n Builds a radio box group for the item, inside a table, with the checkbox on the right side. If "n" is present and is a digit from 2 to 9, it will align the options in that many columns.
check Builds a checkbox group for the item, with spaces separating the elements. check nbsp Builds a checkbox group for the item, with separating the elements. check left n Builds a checkbox group for the item, inside a table, with the checkbox on the left side. If "n" is present and is a digit from 2 to 9, it will align the options in that many columns. check right n Builds a checkbox group for the item, inside a table, with the checkbox on the right side. If "n" is present and is a digit from 2 to 9, it will align the options in that many columns.
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, 'show', which shows the list of possible attributes, and 'display', which shows the label text for the selected option only.
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 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 for an individual line item (set the mv_disount attribute with embedded Perl) 4. 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. The variable $s is saved between
iterations, so the discounts are cumulative. 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 or price adjustments.
To apply a straight 20% discount to all items:
[discount ALL_ITEMS] $s * .8 [/discount]
or with named attributes:
[discount code=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]
To reset a discount, set it to the empty string:
[discount ALL_ITEMS][/discount]
Perl code can be used to apply the discounts, and variables are saved
between items and are shared with the [calc]
tag. This example gives 10% off if two items are ordered, with 5% more for
each additional up to a maximum of 30% discount:
[calc] [item-list] $totalq{"[item-code]"} += [item-quantity]; [/item-list] return ''; [/calc] [item-list] [discount code="[item-code]"] return ($s) if $totalq{"[item-code]"} == 1; return ($s * .70) if $totalq{"[item-code]"} > 6; return ($s * ( 1 - 0.05 * $totalq{"[item-code]"} )); [/discount] [/item-list]
Here is an example of a special 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 [item-discount]
tag.
[item-list] Discount for [item-code]: [item-discount] [/item-list]
Finally, if you want to display the discounted subtotal, you need to use
the [calc]
capability:
[item-list] Discounted subtotal for [item-code]: [currency][calc] [item-price] * [item-quantity] [/calc][/currency] [/item-list]
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]
MiniVend will directly interface with Perl libraries provided by CyberCash, Inc. This allows direct card billing at the time the order is placed. If using CyberCash 2, the module is called CCLib.pm and its version should be 1.3 or greater. If the library is found at startup, the message ``CyberCash 2 module found'' will be displayed.
MiniVend 3.11 and above support CyberCash 3; see the section below for differences when using CyberCash 3.
To use CyberCash 2, 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 CyberCash Perl library module 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:
<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]
CreditCardAuto No CyberCash Yes Variable CYBER_SECRET first-natl Variable CYBER_PORT 8000 Variable CYBER_HOST localhost
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.
MiniVend 3.11 supports CyberCash 3 with the CCMckDirectLib3_2.pm CCMckLib3_2.pm modules. If those modules are in place in your Perl include path (you can use VendRoot/lib as a home if you wish), using CyberCash 3.2 is the same as with CyberCash 2 server except:
Variable CYBER_CONFIGFILE /home/you/mck-lib/conf/merchant.conf
In all likelihood, this will make the values of CYBER_HOST, CYBER_PORT, and CYBER_SECRET moot. It will not hurt anything if they remain set.
Variable CYBER_VERSION 3.2
This allows CyberCash 2 and 3 implementations to coexist on the same machine.
MiniVend has standard sorting options for sorting the search lists, loop lists, and item lists based on the contents of database fields. In addition, adds list slices for 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 ... ]
f case-insensitive sort (folded) (mutually exclusive of n) n numeric order (mutually exclusive of f) r reverse sort
...
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 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 Vertigo, Magic Staircase 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 Vertigo, Magic Staircase 99-102 The Art Store T-Shirt
The tag [sort products:title =3-4]
is equivalent to the above.
[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 Leon Spilliaert Vertigo, Magic Staircase 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:
Leon Spilliaert Vertigo, Magic Staircase 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.
[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.
[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.
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.
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.
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.
[shipping-description]
element).
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:
[calc][item-list] ... [/item-list][/calc]
to create custom shipping routines.
[A-Z]
, by named subroutine if it begins with an s, by a MiniVend chained cost calculation if m or i, and a straight cost otherwise. If it begins with an e, a zero cost is returned with the following string as the error message.
There are 8 ways that shipping cost may be calculated. The method used depends on the first character of the cost field in the shipping database.
ship_message
([data session ship_message]
).
default
.
NOTE: You may use the same mode name for all lines in the same group, but the first one will contain the main criteria.
[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.
global Option n/a 0 0 g PriceDivide rpsg RPS quantity 0 0 R RPS products/rps.csv rpsg RPS quantity 0 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 0 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 150 u upsg [default zip 980] 12.00 round upsg UPS 0 150 u upsg [default zip 980] 2.00 round upsg UPS 150 9999 e @@TOTAL@@ lb too heavy for UPS
upsca UPS/CA weight 0 0 c C UPS_Canada products/can.csv upsca UPS/CA weight -1 -1 o PriceDivide=0 upsca UPS/CA weight 0 150 C upsca [default zip A7G] 5.00 upsca UPS/CA weight 150 99999 e @@TOTAL@@ lb too heavy for UPS fedex FedEx quantity 1 9999 s fedex_cost ;[value country]
[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.
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. If you place it in your products directory, then the directive would
look like:
UPSZoneFile products/450.csv
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.
In the example below, you would want a database specification like:
Database upsg upsg.csv CSV
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.
products/can.csv
) and uses a different database, upsca. It also disables the global PriceDivide option for itself only, not
allowing currency conversion. Otherwise, the process is the same.
You can define up to 27 different lookup zones in the same fashion. If one
of the cost lines (the last field) in the shipping.asc
file begins with a ``c'', it configures another lookup zone, which must be
lettered from A to Z
. It takes the format:
c X name file* length* multiplier*
where
X is the letter from A-Z
. The name is used internally as an identifier and must be present. The
optional file is relative to the catalog root (like UpsZoneFile is) -- if it is not present the file equal to name in the products directory (ProductDir) will be used as the zone file. If the optional digit length
is present, that determines the number of signficant digits in the passed
postal/geo code. When the optional multiplier
is present, the weight is multiplied by it before doing the table lookup.
This allows shipping weights in pounds or kilograms to be adapted to a
table using the opposite as the key. Remember, the match on weight must be
exact, and MiniVend rounds the weight up to the next even unit.
To define the exact equivalent of the UPS lookup zone, you would do:
c U UPS products/450.csv 3 1
The only difference is that the beginning code to call the lookup is
upper-case
U
instead of lower-case u.
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).
The UPS-style lookup uses two files for its purposes, both of which need to be in a format like UPS distributes for US shippers.
The zone file is a file that is usually specific to the originating location. For
US shippers shipping to
US locations, it is named for the first three digits of the originating zip code with a
CSV extenstion -- for example,
450.csv
.
It has a format similar to:
low - high, zone,zone,zone,zone
The low
entry is the low bound of the geographic location -- high
is the high bound. (By geographic location we mean zip code.) If the first digits of the zip code, compared
alphanumerically, fall between the low and high values, that zone is used
as the column name for a lookup in the rate database. The weight is used as the row key.
The first operative row of the zone file (one without leading quotes) is used to determine the zone column name. In the US, it looks something like
Dest. ZIP,Ground,3 Day Select,2nd Day Air,2nd Day Air A.M.,Next Day Air Saver,Next Day Air
MiniVend strips all non-alpha characters and comes up with:
DestZIP,Ground,3DaySelect,2ndDayAir,2ndDayAirAM,NextDayAirSaver,NextDayAir
Therefore, the zone column (shipping type) that you would use use for
UPS ground would be ``Ground'', and that is what the
database should be named. To support the above, you would want a shipping.asc
line that reads:
upsg UPS Ground weight 0 150 u Ground [default zip 983]
and a catalog.cfg
database callout of:
Database Ground Ground.csv CSV
You can change these column names as long as they correspond to the identifier of your rate database.
The rate database is a standard MiniVend database. For US shippers, UPS distributes their rates in a fairly standard comma-separated value format, with weight being the first (or key) column and the remainder of the columns corresponding to the zone -- which you obtain from the lookup in the zone file.
To adapt other shipper zone files to MiniVend's lookup, you will need to make it fit the UPS US format. (Most of the UPS international files don't follow the US format). For example, the 1998 Ohio-US to Canada file begins:
Canada Standard Zone Charts from Ohio Locate the zone by cross-refrencing the first three characters of the destination Postal Code in the Postal Range column. Postal Range Zone A0A A9Z 54 B0A B9Z 54 C0A C9Z 54 E0A E9Z 54 G0A G0A 51 G0B G0L 54 G0M G0S 51 G0T G0W 54
You need to change it to
Destination,canstnd A0A-A9Z, 54 B0A-B9Z, 54 C0A-C9Z, 54 E0A-E9Z, 54 G0A-G0A, 51 G0B-G0L, 54 G0M-G0S, 51 G0T-G0W, 54
and match it with a canstnd
CSV database that looks like
Weight,51,52,53,54,55,56 1,7.00,7.05,7.10,11.40,11.45,11.50 2,7.55,7.65,7.75,11.95,12.05,12.10 3,8.10,8.15,8.40,12.60,12.70,12.85 4,8.65,8.70,9.00,13.20,13.30,13.55 5,9.20,9.25,9.75,13.85,13.85,14.20 6,9.70,9.85,10.35,14.45,14.50,14.90 7,10.25,10.40,11.10,15.15,15.15,15.70 8,10.80,10.95,11.70,15.70,15.75,16.35 9,11.35,11.55,12.30,16.40,16.45,17.20
and is called out in catalog.cfg with:
Database canstnd canstnd.csv CSV
With the above, a 4-pound shipment to postal code E5C 4TL would yield a cost of 13.20.
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 150 u Ground [value zip] 12.00 upsg UPS Ground 0 150 u Ground [value zip] 3.00
If upsg is the mode selected, the value of the user session variable
state is examined to see if it matches the geographic qualification on a
whole-word boundary. If it is AK
or HI
, then
UPS Ground with an adder of 12 will be selected; if it ``falls through'', then
UPS Ground with an adder of 3 will be selected.
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.
MiniVend has a user database function which allows customers to save any pertinent values from their session. It also allows the setting of database or file access control lists for use in controlling access to pages and databases on a user-by-user basis.
The database field names in the user database correspond with the form
variable names in the user session. If you have a column named address
, then when the user logs in the contents of that field will be placed in
the form variable address
, and will then be availabe for display with [value address]
. Similarly, the database value is available with
[data table=userdb column=address key=username]
.
The
ASCII file for the database will not reflect changes
unless you export the file with [tag export userdb][/tag]
. It is not advisable to edit the
ASCII file, as it will overwrite the real data that is in the
DBM table; user logins and changes would be lost. (This would not happen with
SQL, but editing the
ASCII file would have no effect.) You should probably set the
NoImport configuration directive accordingly.
This section describes the user database in MiniVend 3.12. Prior to 3.12,
the user database was a demonstration add-on module with a global
subroutine interface. Some of the concepts were the same; the module
interface is much the same; and page code based on the previous version
should work if the userdb.cfg
file is still there.
The field names to be used are not set in concrete; they may be changed with options, and fields may be added or subtracted at any time. Most users will choose to keep the default demo fields for simplicity sake, as they cover most common needs. As distributed in the demo, the fields are:
code accounts acl address address_book b_address b_city b_country b_name b_nickname b_phone b_state b_zip carts city country db_acl email email_copy fax fax_order file_acl mv_credit_card_exp_month mv_credit_card_exp_year mv_credit_card_info mv_credit_card_type mv_shipmode name order_numbers p_nickname password phone_day phone_night preferences s_nickname state time zip
A few of those fields are special in naming, though all can be changed via an option. A couple of the fields are reserved for Minivend's use.
IMPORTANT NOTE: If you are not running with PGP or other encryption for your credit card numbers, which should NEVER be done anyway, then it is important that you remove the mv_credit_card_info field from the database.
The special database fields are:
accounts Storage for billing accounts book address_book Storage for shipping address book b_nickname Nickname of current billing account carts Storage for shopping carts p_nickname Nickname for current preferences preferences Storage for preferences s_nickname Nickname for current shipping address db_acl Storage for database access control lists file_acl Storage for file access control lists acl Storage for simple integrated access control
If not defined, the corresponding capability is not available.
NOTE: The fields accounts
, address_book
, carts, and preferences
should be defined as a
BLOB type if you are using
SQL. This is also suggested for the acl fields if those lists could be large.
Reserved fields include:
code The username (key for the database) password Password storage time Last time of login
MiniVend provides a [userdb ...]
tag to access the UserDB functions.
[userdb function=function_name username="username"* assign_username=1 username_mask=REGEX* password="password"* verify="password"* oldpass="old password"* crypt="1|0"* shipping="fields for shipping save" billing="fields for billing save" preferences="fields for preferences save" ignore_case="1|0"* force_lower=1 param1=value* param2=value* ... ]
* Optional
It is normally called in an mv_click
or mv_check
setting, as in:
[set Login] mv_todo=return mv_nextpage=welcome [userdb function=login] [/set]
<FORM ACTION="[process-target]" METHOD=POST> <INPUT TYPE=hidden NAME=mv_click VALUE=Login> Username <INPUT NAME=mv_username SIZE=10> Password <INPUT NAME=mv_password SIZE=10> </FORM>
There are several global parameters that apply to any use of the userdb
functions. Most importantly, by default the database table is set to be userdb. If you must use another table name, then you should include a database=table
parameter with any call to userdb
. The global parameters (default in parens):
database Sets user database table (userdb) show Show the return value of certain functions or the error message, if any (0) force_lower Force possibly upper-case database fields to lower case session variable names (0) billing Set the billing fields (see Accounts) shipping Set the shipping fields (see Address Book) preferences Set the preferences fields (see Preferences) bill_field Set field name for accounts (accounts) addr_field Set field name for address book (address_book) pref_field Set field name for preferences (preferences) cart_field Set field name for cart storage (carts) pass_field Set field name for password (password) time_field Set field for storing last login time (time) expire_field Set field for expiration date (expire_date) acl Set field for simple access control storage (acl) file_acl Set field for file access control storage (file_acl) db_acl Set field for database access control storage (db_acl)
By default the system crypt()
call will be used to compare the
password. This is best for security, but the passwords in the user database
will not be human readable.
If you don't keep critical information and don't do MiniVend administration
via the UserDB
capability, then you may wish to use the <UserDB> directive
(described below) to set encryption off by default:
UserDB default crypt 0
That will set encryption off by default. You can still set encryption on by
passing crypt=1
with any call to a new_account, change_pass, or login call.
The UserDB directive provides a way to set defaults for the user database. For
example, if you always wanted to save and recall the scratch variable tickets
in the user database instead of the form variable tickets
, you could set:
UserDB default scratch tickets
That makes every call to [userdb function=login]
be equivalent to [userdb function=login scratch=tickets]
.
If you wish to override that default for one call only, you can use [userdb function=login scratch="passes"]
.
If you wish to log failed access authorizations, set the UserDB
profile parameter log_failed
true:
UserDB default log_failed 1
To disable logging of failed access authorizations (the default), set the UserDB
profile parameter log_failed
to 0:
UserDB default log_failed 0
The UserDB directive uses the same key-value pair settings as the Locale and Route directives, and you may have more than one set of defaults. You can set them in a hash structure:
UserDB crypt_case <<EOF { 'scratch' => 'tickets', 'crypt' => '1', 'ignore_case' => '0', } EOF
UserDB default <<EOF { 'scratch' => 'tickets', 'crypt' => '1', 'ignore_case' => '1', } EOF
NOTE: The usual here-document caveats apply -- the EOF must be on a line by itself with no leading/trailing whitespace.
The last one to be set becomes the default.
The option profile selects the set to use. So if you wanted usernames and passwords to be case sensitive with no encryption, you could pass this call:
[userdb function=new_account profile=case_crypt]
The username and password will be stored as typed in, and the password will be encrypted in the database.
The user database features are implemented as a series of functions
attached to the userdb
tag. The functions are:
Log in to Minivend. By default, the username is contained in the form
variable mv_username
and the password in mv_password
. If the login is successful, the session value username
([data session username]
) will be set to the user name.
This will recall the values of all non-special fields in the user database and place them in their corresponding user form variables.
The CookieLogin directive (catalog.cfg) allows users to save their username/password in a
cookie. Expiration time is set by
SaveExpire, renewed every time they log in. To cause the cookie to be generated
originally, the form variable mv_cookie_password
or
mv_cookie_username
must be set in the login form. The former causes both username and password
to be saved, the latter just the username.
Create a new account. It requires the username
, password
, and
verify
parameters, which are by default contained in the form variables mv_username
, mv_password
, mv_verify
respectively.
If you set the assign_username
parameter, then UserDB will assign a sequential username. The counter parameter can be used to set the filename (must be absolute), or you can accept the default of CATALOG_DIR/etc/username.counter. The first username will be
``U0001'' if the counter doesn't exist already.
The ignore_case
parameter forces the username and password to lower case in the database,
in effect rendering the username and password case-insensitive.
If you set username_mask
to a valid Perl regular expression (without the surrounding / /) then any
username containing a matching string will not be allowed for use. For
example, to screen out order numbers from being used by a random user:
[userdb function=new_account username_mask="^[A-Z]*[0-9]" ]
The CookieLogin directive (catalog.cfg) allows users to save their username/password in a
cookie. Expiration time is set by
SaveExpire, renewed every time they log in. To cause the cookie to be generated
originally, the form variable mv_cookie_password
or
mv_cookie_username
must be set in the login form. The former causes both username and password
to be saved, the latter just the username.
If you want to automatically create an account for every order, you can do in the OrderReport file:
[userdb function=new_account username="[value mv_order_number]" password="[value zip]" verify="[value zip]" database="orders" ]
This would be coupled with a login form that asked for order number and zip code; thereupon allowing you to display the contents of a transaction database with (presumably updated) order status information or a shipping company tracking number.
Change the password on the currently logged-in account. It requires the username
, password
, verify
, and oldpass
parameters, which are by default contained in the form variables mv_username
,
mv_password
, mv_verify
, mv_oldpass
respectively.
Place an entry in the shipping Address book. Example:
[userdb function=set_shipping nickname=Dad]
See Address Book below.
Recall an entry from the shipping Address book. Example:
[userdb function=get_shipping nickname=Dad]
See Address Book below.
Gets the names of shipping address book entries and places them in the
variable address_book
. By default, it does not return the values; if you wish them to be
returned you can set the parameter show
to 1, as in:
[set name=shipping_nicknames interpolate=1] [userdb function=get_shipping_names show=1] [/set]
Place an entry in the billing accounts book. Example:
[userdb function=set_billing nickname=discover]
See Accounts Book below.
Recall an entry from the billing accounts book. Example:
[userdb function=get_billing nickname=visa]
See Accounts Book below.
[userdb function=set_cart nickname=christmas]
See Carts below.
Recall a saved shopping cart.
[userdb function=get_cart nickname=mom_birthday]
Setting target
saves to a different shopping cart than the default main cart. The carts_field
controls the database field used for storage.
Set a simple acl. Example:
[userdb function=set_acl location=cartcfg/editcart]
This allows the current user to access the page ``cartcfg/editcart'' if it is access-protected.
To delete access, do:
[userdb function=set_acl location=cartcfg/editcart delete=1]
To display the setting at the same time as setting use the
show
attribute:
[userdb function=set_acl location=cartcf/editcart show=1]
Checks the simple access control listing for a location, returning 1 if allowed and the empty string if not allowed.
[if type=explicit compare="[userdb function=check_acl location=cartcfg/editcart]" ] [page cartcfg/editcart]Edit your cart configuration[/page] [/if]
Sets a complex access control value. Takes the form:
[userdb function=set_file_acl mode=rw location=products/inventory.txt]
where mode is any value you wish to check for with check_file_acl. As with the simple ACL, you can use delete=1 to delete the location entirely.
Checks a complex access control value and returns a true/false (1/0) value. Takes the form:
[userdb function=check_db_acl mode=w location=inventory]
where mode is any value you wish to check for with check_file_acl. It will return true if the mode string is contained within the entry for that location. Example:
[if type=explicit compare="[userdb function=check_db_acl mode=w location=inventory]" ] [userdb function=set_acl location=cartcfg/edit_inventory] [page cartcfg/edit_inventory]You may edit the inventory database[/page] [else] [userdb function=set_acl location=cartcfg/edit_inventory delete=1] Sorry, you can't edit inventory. [/if]
address_book is a shipping address book. The shipping address book saves information relevant to shipping the order. In its simplest form, this can be the only address book needed. By default these form values are included:
s_nickname name address city state zip country phone_day mv_shipmode
The first field is always the name of the form variable that contains the key for the entry.
The values are saved with the [userdb function=set_shipping]
tag call, and are recalled with [userdb function=get_shipping]
.
A list of the keys available is kept in the form value address_book
, suitable for iteration in an
HTML select box or in a set of links.
You can get the names of a the addresses with the get_shipping_names function:
[userdb function=get_shipping_names]
By default, they are placed in the variable address_book
. Here is a little snippet that builds a select box:
<FORM ACTION="[process-target]" METHOD=POST> [userdb function=get_shipping_names] [if value address_book] <SELECT NAME="s_nickname"> [loop arg="[value address_book]"] <OPTION> [loop-code] [/loop] </SELECT> <INPUT TYPE=submit NAME=mv_check VALUE="Recall Shipping"> </FORM>
The same principle works with accounts , carts, and preferences.
To restore a cart based on the above, you can place in an mv_check
routine:
[set Recall Shipping] mv_todo=return mv_nextpage=ord/basket [userdb function=get_shipping nickname="[value s_nickname]"] [/set]
When the mv_check variable is encountered, the contents of the scratch
variable Recall Shipping
are processed and the shipping address information inserted into the user
form values. This is destructive of any current values of those user
session variables, of course.
If you want to change the fields that are recalled or saved, you can use the shipping parameter:
[userdb function=get_shipping nickname=city_and_state shipping="city state"]
Only the values of the city
and state variables will be replaced.
The accounts book saves information relevant to billing the order. By default these form values are included:
b_nickname b_name b_address b_city b_state b_zip b_country b_phone mv_credit_card_type mv_credit_card_exp_month mv_credit_card_exp_year mv_credit_card_info
The values are saved with the [userdb function=set_billing]
tag call, and are recalled with [userdb function=get_billing]
.
A list of the keys available is kept in the form value accounts
, suitable for iteration in an
HTML select box or in a set of links.
Preferences are miscellaneous session information. They include by default the fields:
email fax phone_night fax_order
The field p_nickname acts as a key to select the preference set. You can
change the values that are included with the preferences
parameter: [userdb function=set_preferences preferences=``email_copy email
fax_order fax'']
You may save or recall the contents of shopping carts in much the same
fashion. See the simple demo application ord/basket.html
page for an example.
You can implement a simple access control scheme with the MiniVend user
database. Controlled pages must reside in a directory which has a file
named .access
that is zero bytes in length. (If it is more than 0 bytes, then only the RemoteUser or MasterHost may access files in that directory.)
Set the following variables in catalog.cfg
:
Variable MV_USERDB_ACL_TABLE userdb Variable MV_USERDB_ACL_COLUMN acl
The MV_USERDB_ACL_TABLE
is the table which controls access, and likewise the MV_USERDB_ACL_TABLE
names the column in that database which will be checked for authorization.
The database entry should contain the complete MiniVend-style page name of the page to be allowed. It will not match substrings.
For example, if the user flycat
followed this link:
<A HREF="[area cartcfg/master_edit]">Edit</A>
Access would be allowed if the contents of the userdb were:
code acl flycat cartcfg/master_edit
and disallowed if it were:
code acl flycat cartcfg/master_editor
You can enable access with:
[userdb function=set_acl location="cartcfg/master_edit"]
and disallow access with:
[userdb function=set_acl delete=1 location="cartcfg/master_edit"]
Of course a pre-existing database with the ACL values will work as well; it need not be in the UserDB setup.
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.
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.
Once the order report is processed, you can be sure the order will complete. Therefore it is the perfect place to put MiniVend tags that make order entries in database tables.
A good model is to place a single record in a database summarizing the order, and a series of lines that correspond to each line item in the order. This can be in the same database table; if the order number itself is the key for the summary, you can append a line number to the order number to show each line of the order.
The following would summarize a sample order number S00001 for part number 00-0011 and 99-102:
code order_number part_number quantity price shipping tax S00001 S00001 3 2010 12.72 100.50 S00001-1 S00001 00-0011 2 1000 UPS yes S00001-2 S00001 99-102 1 10 UPS yes
You can add fields as appropriate, perhaps with order status, shipping tracking number, address, customer number, or other information.
The above can be easily done with MiniVend's [import ....]
tag using the convenient NOTES
format:
[set import_status] [import table=orders type=LINE continue=NOTES]
code: [value mv_order_number] order_number: [value mv_order_number] quantity: [nitems] price: [subtotal noformat=1] shipping: [shipping noformat=1] tax: [salestax noformat=1]
[/import] [item-list] [import table=orders type=LINE continue=NOTES]
code: [value mv_order_number]-[item-increment] order_number: [value mv_order_number] quantity: [item-quantity] price: [item-price noformat=1] shipping: [shipping-description] tax: [if-field nontaxable]No[else]Yes[/else][/if]
[/import][/item-list]
MiniVend can send order emails and perform custom credit card charges
and/or logging for each individual item. The Route directive is used to control this behavior, along with the mv_order_route
item attribute and mv_order_route
form variable.
Routes are established with the Route directive, which is similar to the Locale directive. Each route is like a locale, in that you can set key-value pairs. Here is an example setting:
Route VEN pgp_key 0x67798115 Route VEN email orders@minivend.com Route VEN reply service@minivend.com Route VEN encrypt 1 Route VEN encrypt_program "/usr/bin/pgpe -fat -q -r %s" Route VEN report etc/report_mail
This route would be used whenever the value VEN
was contained in the form variable mv_order_route
.
The last route that is defined provides the defaults for all other routes. For example, if encrypt_program is set there then the same value will be the default for all routes.
The attributes that can be set are:
OrderCounter
for this route. It will generate a different value for mv_order_number
for the route.
Route VEN cybermode mauthonly Route VEN CYBER_CONFIGFILE config/vendor1_cfg Route VEN CYBER_VERSION 3.2
address(es)
where the order should be sent. Set just
like the MailOrderTo directive, which is also the default.
pgpe -fat -r %s
.
Errors-To:
email header so that bounced orders will go to the proper address. Default
is the same as MailOrderTo.
mv_order_number
. This can be useful for batching orders via download.
pgpk -l
.
pgpk -l
.
Reply-To
header that should be set. Default is the same as email.
If there are only word characters (A-Za-z0-9 and underscore) then it describes a MiniVend variable name where the address can be found.
An individual item routing causes all items labeld with that route to be
placed in a special sub-cart which will be used for the order report. This
means that the [item-list] LIST [/item-list]
will only contain those items, allowing operations to be performed on
subsets of the complete order.
Here is an example of an order routing:
Route HARD pgp_key 0x67798115 Route HARD email hardgoods@minivend.com Route HARD reply service@minivend.com Route HARD encrypt 1 Route HARD encrypt_program "/usr/bin/pgpe -fat -q -r %s" Route HARD report etc/report_mail Route SOFT email "" Route SOFT profile create_download_link Route SOFT empty 1
Route main cybermode mauthonly Route main CYBER_VERSION 3.2 Route main CYBER_CONFIGFILE etc/cybercash.cfg Route main pgp_key 0x67798115 Route main email orders@minivend.com Route main reply service@minivend.com Route main encrypt 1 Route main encrypt_program "/usr/bin/pgpe -fat -q -r %s" Route main report etc/report_all To tell MiniVend that order routing is in effect, the variable mv_order_route is set on the B<final> order submission form:
<INPUT TYPE="hidden" NAME="mv_order_route" VALUE="main">
To set the order routing for individual items, some method of determining
their status must be made and the mv_order_route
attribute must be set. This could be set at the time of the item being
placed in the basket, or you can have a database field called goods_type
set to the appropriate value. We will use this Perl routine on the final
order form:
[perl arg=carts interpolate=1] my $string = <<'EOF'; [item-list][item-code] [item-field goods_type] [/item-list] EOF my @items; my %route; @items = grep /\S/, split /\n+/, $string; for(@items) { my ($code, $keycode) = split /\t/, $_; $route{$code} = $keycode; } my $cart = $Safe{'carts'}{'main'}; my $item; foreach $item ( @{ $Safe{'carts'}{'main'} } ) { $item->{mv_order_route} = $route{$item->{'code'}} || undef; } return ''; [/perl]
Now the individual items are labeled with a mv_order_route
value which will cause their inclusion in the appropriate order routing.
Upon submission of the order form, any item labeled HARD
will be accumulated and sent to the email address hardgoods@minivend.com
, where presumably the item will be pulled from inventory and shipped.
Any item labeled SOFT
will be passed to the order profile
create_download_link
, which will place it in a staging area for customer download. (This would
be supported by a link on the receipt, perhaps by reading a value set in
the profile).
The main
order routing will use CyberCash to charge the order, and will be
completely encrypted for emailing.
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 a form action of
[process-target secure=1]
. An individual page can be displayed via
SSL with [page href=mvstyle_pagename secure=1]
.
A certain page can be set to be always secure with the AlwaysSecure
catalog.cfg directive.
MiniVend incorporates additional security for credit card numbers. The field mv_credit_card_number will not ever be written to disk.
To enable automated encryption of the credit card information, 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/bin/pgpe -fat -r sales@company.com
See CreditCardAuto for more information on how to set the form variables.
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. See MasterHost, RemoteUser, and Password.
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 the catalog administrator.
If the directory containing the page has a file .access
and that file is zero bytes long, then access can be gated in one of
several ways.
.access_gate
is present, it will be read and scanned for page-based access. The file has
the form:
page: condition *: condition
The page
is the file name of the file to be controlled (the .html extension is
optional); the condition
is either a literal Yes/No
or MiniVend tags which would produce a Yes
or No
(1/0 work just fine, as do true/false).
The entry for *
sets the default action if the page name is not found. If you want pages to
be allowed by default, set it to 1
or Yes
. If you want pages to be denied by default in this directory, leave blank
or set to No
. Here is an example, for the directory controlled
, having the following files:
-rw-rw-r-- 1 mike mike 0 Jan 8 14:19 .access -rw-rw-r-- 1 mike mike 185 Jan 8 16:00 .access_gate -rw-rw-r-- 1 mike mike 121 Jan 8 14:59 any.html -rw-rw-r-- 1 mike mike 104 Jan 8 14:19 bar.html -rw-rw-r-- 1 mike mike 104 Jan 8 14:19 baz.html -rw-rw-r-- 1 mike mike 104 Jan 8 14:19 foo.html
The contents of .access_gate
:
foo.html: [if session username eq 'flycat'] Yes [/if] bar: [if session username eq 'flycat'] [or scratch allow_bar] Yes [/if] baz: yes *: [data session logged_in]
The page controlled/foo
is only allowed for the logged-in user
flycat.
The page controlled/bar
is allowed for the logged-in user
flycat, or if the scratch variable allow_bar
is set to a non-blank, non-zero value.
The page controlled/baz
is always allowed for display.
The page controlled/any
(or any other page in the directory not named in .access_gate
) will be allowed for any user logged in via UserDB.
NOTE: The .access_gate
scheme is available for database access checking if the database is defined
as an AdminDatabase. The .access_gate
file is located in ProductDir.
MV_USERDB_REMOTE_USER
is set (non-zero and non-blank) then any user logged in via the UserDB
feature will receive access to all pages in the directory.
NOTE: If there is a .access_gate
file, it overrides this.
MV_USERDB_ACL_TABLE
is set to a valid database identifier, the UserDB module can control access with simple
ACL logic. See USER DATABASE.
NOTE: If there is a .access_gate
file, it overrides this. Also, if
MV_USERDB_REMOTE_USER is set, then this capability is
not available.
MiniVend has several features which help control page appearance.
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>.
NOTE: To be compatible with HTML editors, it is recommended you use the HTML syntax for this tag:
<BODY MV="body 1">
All references to [body N]
can be assumed to mean this call.
If an extra bit of text is included after the scheme number, then it will be appended to the body tag. This allows JavaScript and other things to be inserted. It is appended, and for most browsers this means that previous definitions made by the numbered scheme will be overridden.
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.
NOTE: [buttonbar] is deprecated in favor of Variable.
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 page frame]
or [area page]
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.)
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.
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.
NOTE: This feature is deprecated and should not be used in new installations.
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.
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 se=...]
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:
.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.)
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.
The locale could be set to fr_FR
(French for France) in one of two ways:
[old]
.
Immediately sets the locale to locale
, and will cause it to persist in future user pages if the persist
is set to a non-zero, non-blank value. If the currency
attribute is set, modifies the pricing and currency-specific locale keys
and MiniVend configuration directives to that locale. If there are no
arguments, sets it back to the user's default locale as defined in the
scratch variables mv_locale
and
mv_currency
.
This allows:
Dollar Pricing:
[setlocale en_US] [item-list] [item-code]: [item-price]<BR> [/item-list]
Franc Pricing:
[setlocale fr_FR] [item-list] [item-code]: [item-price]<BR> [/item-list]
[comment] Return to the user's default locale [/comment] [setlocale]
This tag is only available in new mode (``NewTags Yes'' or [new]
).
[page catalog]
, except when the link is followed it will set the locale to fr_FR
before displaying the page. This is persistent.
[page catalog]
, except when the link is followed it will set the locale to fr_FR
and the pricing/number display to the locale en_US
before displaying the page. This is persistent.
Once the locale is persistently set for a user, it is in effect for the duration of their session.
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 displayed. 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 recognized.
You can also use a database to set locale information. It is added to any in the catalog.cfg file, and values in it will overwrite previous settings. See LocaleDatabase.
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.
Since the [L] message [/L]
substitution is done before any tag processing, you cannot do [L][item-data table field][/L]
and expect success. There is an add-on [loc] message [/loc]
UserTag supplied with the distribution beginning at
V3.09. It does the same thing as [L] [/L]
except after all tag substitution is done. See minivend.cfg.dist for the definition.
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.
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:
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
.
[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
**,***.**
.
If you set Locale keys corresponding to some MiniVend catalog.cfg
directives, those values will be set when setting the locale.
# Establish the default at startup PageDir english Locale fr_FR PageDir francais Locale en_US PageDir english
# Establish the default at startup ImageDir /images/english/ Locale fr_FR ImageDir /images/francais/ Locale en_US ImageDir /images/english/
# 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.
# 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.
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
# 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.
# Default at startup PriceAdjustment format Locale fr_FR PriceAdjustment formats
[item-description]
and
[description code]
tags.
# Establish the default at startup DescriptionField description Locale fr_FR DescriptionField desc_fr
[locale key]
and [/locale]
tags. See the example above.
The MiniVend [sort database:field]
keys will use the
LC_COLLATE setting for a locale provided that:
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 has the capability to read its locale information from a database, named with the LocaleDatabase directive. The database can be of any valid MiniVend type. The locales are in columns, and the keys are in rows. So to set up price information:
key en_US fr_FR de_DE PriceDivide 1 .1590 .58 mon_decimal_point . , , mon_thousands_sep , . currency_symbol $ frs DM ps_cs_precedes 1 0 0
That would translate exactly into:
Locale en_US PriceDivide 1 Locale en_US mon_decimal_point . Locale en_US mon_thousands_sep , Locale en_US currency_symbol $ Locale en_US ps_cs_precedes 1
Locale fr_FR PriceDivide .1590 Locale fr_FR mon_decimal_point , Locale fr_FR mon_thousands_sep . Locale fr_FR currency_symbol " frs" Locale fr_FR ps_cs_precedes 0
Locale de_DE PriceDivide .58 Locale de_DE mon_decimal_point , Locale de_DE mon_thousands_sep " " Locale de_DE currency_symbol "DM " Locale de_DE ps_cs_precedes 1
These settings add on to but overwrite any that are set in the catalog configuration files, including any #include files.
IMPORTANT NOTE: The information is only read on catalog configuration. It is not reasonable to access a database for translation or currency conversion in the normal course of events.
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.
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, only the special MiniVend admin catalog will be started.
The directives defined in minivend.cfg affect the entire MiniVend server and all catalogs running under it; though you may run multiple MiniVend servers on the same machine with totally independent operation.
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
A space or colon-separated list of users who have global MiniVend administration permission for the special mv_admin catalog. The password is encrypted unless the Global Variable MV_NO_CRYPT is set to a true value. This is the case in the distribution minivend.cfg file, which has these settings:
Variable MV_NO_CRYPT AdminUser minivend:nevairbe
Obviously you should change the password at your first opportunity. To
begin with, the catalog is defined with a MasterHost value of 127.0.0.1 to disallow access from the outside world. To access it
from another system besides localhost
, you will need to remove or change the value.
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
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.
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
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.
DomainTail No
If you are encrypting your credit cards with PGP or GPG, or are using a payment service like CyberCash, you may want to look at the WideOpen directive, which enables more browser compatibility at the cost of some security.
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
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
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.
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
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
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
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
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
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
If non-zero, enables a check of running MiniVend processes during the housekeeping routine. If a process has been running (or is hung) for longer than PIDcheck seconds then a kill -9 will be issued and the server count decremented.
During the housekeeping routine, the number of servers checked by MaxServers will be recounted based on PID files.
Default is 0, disabling the check. It is recommended that you use this only for MiniVend 3.12 or higher, and it is recommended that you do use it for that version.
PIDcheck 300
If you have long-running database builds, you will need to disable this, set it to a high value (perhaps 600, for 10 minutes), or use the offline script.
NOTE: This directive no longer applies as of MiniVend 3.12.
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
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
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
A value of 'none' will disable the sending of emailed orders. Orders must be read from a tracking file, log, or by other means.
Allows definition of a catalog which shares most of the characteristics of another catalog. Only the directives 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
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
When running in
INET mode, using tlink
or the internal
HTTP server, specifies the port(s)
which
will be monitored. by the MiniVend server. Default is 7786, which is mapped
to the special mv_admin catalog.
To use the internal
HTTP server (perhaps only for password-protected
queries), you can map a catalog to a port. If you had three catalogs
running on the server www.minivend.com, named simple, sample
, and search, you might have in the directive:
TcpPort 7786 mv_admin 7787 simple 7788 sample 7789 search
NOTE: To map large numbers of ports, you can use the <<MARKER here document notation in minivend.cfg.
With this in effect, the internal HTTP server would map the following addresses:
http://www.minivend.com:7786 mv_admin http://www.minivend.com:7787 simple http://www.minivend.com:7788 sample http://www.minivend.com:7789 search
NOTE: This does not pertain to the use of tlink
, which still relies on the
CGI
SCRIPT_PATH.
To enable this, the
SCRIPT_PATH aliases /simple, /sample, etc. must be set
in the Catalog
directive. This would look like:
Catalog simple /home/minivend/catalogs/simple /cgi-bin/simple /simple
This is superceded by the TcpMap directive. It will still accept only a number, but it is not used. (The Global::TcpPort) variable is now used to signify which monitored port is connected.
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
This defines a UserTag which is global in nature, meaning not limited by the Safe.pm module, and which tag is available to all MiniVend catalogs running on the server. Otherwise this is the same as a catalog UserTag.
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
There are several standard variables which you should not use:
AdminUser
.
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.
In the catalog configuration file, the directives MailOrderTo and VendURL are required. They are not defined with defaults, and no catalog will operate unless and until they are set with a value.
Specifies the base URL that will run vlink as a cgi-bin program.
VendURL http://machine.company.com/cgi-bin/vlink
Specifies the email address to mail completed orders to.
MailOrderTo orders@xyzcorp.com
These directives all have default values and are optional.
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
This directive can be set in the DirectiveDatabase.
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
If the file .access_gate
is present in the products directory, the database name will be checked
according to the same scheme as for page access checking. See MINIVEND SECURITY.
page(s).
AdminPage config/menu
AlwaysSecure checkout
AsciiBackend |/usr/order/scripts/place_order
AsciiTrack etc/orders.txt
BackendOrder name,address,city,state,zip,mv_shipmode
[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 _blank
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 Yes
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
has been changed to support a chained pricing scheme. The following text
describes the old definition of CommonAdjust when used in concert with PriceAdjustment. See
Price Maintenance with 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 variables
CookieDomain .yourdomain.com
More than one domain can be set. It must have at least two periods or browsers will ignore it.
mv_cookie_password
or mv_cookie_username
must be set. The former causes both username and password to be saved, the
latter just the username.
CookieLogin Yes
Default is No
.
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.
This option uses the following standard fields on MiniVend order processing forms:
PGP is recommended as the encryption program, though you should remember that US commercial organizations may require a license for RSA. MiniVend will work with GPG, the Gnu Privacy Guard.
CreditCardAuto Yes
CustomShipping Yes
CyberCash Yes
DataDir /user/data
[data database field key]
tag. Database names are restricted to the alphanumeric characters
(including the underscore). See DATABASES.
Database BookReviews reviews.txt 3
mv_ship_mode
. If not set in catalog.cfg, it is default.
DefaultShipping UPS
Delimiter PIPE
IMPORTANT NOTE: It is not recommended that you use CSV, as it prevents MiniVend's enhanced search features from working properly. It is also very slow for importing large databases.
[item-description]
element.
DescriptionField ProductDescription
Default is description. It is no longer a fatal error if this field does not exist.
DisplayErrors Yes
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.
%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 /home/minivend/error.log
ExtraSecure Yes
FieldDelimiter Tilde ~ RecordDelimiter Tilde \n Database mydata mydata.txt Tilde
[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.
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 Yes
FrameFlyPage fr_flypage
It is not an absolute path, but is relative to StaticDir. Default is
framefly
.
A StaticDir of /var/www/htdocs/simple/pages would yield a FrameLinkDir location of
/var/www/htdocs/simple/pages/framefly.
FrameLinkDir frames
FrameOrderPage fr_order
FrameSearchPage fr_resul
FramesDefault Yes
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 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 /images/ /thiscatalog/images/
ImageDir /images/
Can be set in the Locale settings to allow different image sets for different locales (MV3.07 and up).
http://
.
ImageDirInternal http://www.server.name/images/
http://
.
ImageDirSecure /secure/images/
This is useful if you are using a separate HTTPS and HTTP server, and cannot make the image directory path heads match.
[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/
[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">
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.
Database locale_info locale_info.asc TAB LocaleDatabase locale_info
etc/log
.
LogFile etc/log
MasterHost 10.10.10.1
MixMatch yes
MsqlDB catalog
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 BEGIN /images/blue_pap.gif 0 /images/temple.jpg
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
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
[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
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
[page name arg]
tag, among others).
This should probably be set to Yes
for new catalogs.
NewEscape Yes
$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
[old]
tag at the very top of the page, or by surrounding older sections of code
with the
[compat] MINIVEND TAGS [/compat]
tag pair. Default is No.
NewTags No
NoCache ord NoCache special
database(s)
will never be subject to import. Useful for
SQL databases, or databases that will *never* change.
NoImport inventory
NonTaxableField wholesale
OfflineDir /usr/data/minivend/offline
OldShipping Yes
OrderCounter etc/order.number
OrderFrame _blank
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 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 /data/order-form
PageCache yes
PageDir /data/catalog/pages
Can be set in the Locale settings to allow different page sets for different locales (MV3.07 and up).
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 display_page
Variable STORE_ID topshop ParseVariables Yes StaticDir /home/__STORE_ID__/www/cat ParseVariables No
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.
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.
Numbers that begin with an equals sign (=
) are used as absolute prices -- and are interpolated for MiniVend tags
first, so you can use subroutines to set the price. To facilite
coordination with the subroutine, the session variables item_code
and item_quantity
are set to the code and quantity of the item being evaluated. They would be
accessed in a global subroutine with $Vend::Session-
>{item_code}
and $Vend::Session-
>{item_quantity}
.
The pricing information must always come from a database because of security.
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 10 25 50 100 1000
[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 100
Can be set in the Locale settings to allow a price adjustment factor for different currencies (MV3.07 and up).
[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 /data/catalog/for-sale
Most people never set this directive and use the default of products.
ProductFiles vendor_a vendor_b
The key thing about this is that each will be searched in sequence for a
product code to order or an [item-field ....]
or [loop-field ...]
to insert. The main difference between [item-field ....]
and
[item-data table ...]
is this fall-through behavior.
Default is products.
[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
user
, group
, or 'world'.
ReadPermission group WritePermission group
ReceiptPage receipt
FieldDelimiter Tilde ~ RecordDelimiter Tilde \n Database mydata mydata.txt Tilde
RemoteUser Billyboy
ReportIgnore credit_card_no
RequiredFields name,company,email,address,city,state,zip
RobotLimit 200
[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 zip,state
SaveExpire 8 weeks
ScratchDir /tmp
SearchCache Yes
SearchFrame main
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.
https:
protocol definition. Default is blank, disabling secure access.
SecureURL https://machine.com/xyzcorp/cgi-bin/vlink
SendMailProgram /usr/sbin/sendmail
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 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.
s(econds),
m(inutes),
h(ours),
d(ays),
or w(eeks).
SessionExpire 4 hours
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 5.00
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 Yes
[tag flag build][/tag]
on the page in question.)
StaticAll Yes
StaticDepth 2
StaticDir /home/you/www/catalog
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 info/about_us info/terms_and_conditions
StaticPath /catalog
StaticPattern ^info|^help
.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
[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.
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 UT,NV,94024
Most users now use the simpler and more flexible Easy ASCII Tracking capability.
TransparentItem option
mv_shipmode
.
A user database named the same as the mv_shipmode variable must be present or the lookup will return zero.
<IMPORTANT NOTE:> You must obtain the zone information and updated pricing from UPS in order for this to work properly. The zone information is specific to your region!
UpsZoneFile /usr/minivend/data/ups_zone.asc
[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
quantity
-- it will not do what you want.
UseModifier size,color
Variable DOCUMENT_ROOT /usr/local/etc/httpd/htdocs
Database variable variable.asc TAB VariableDatabase variable
Only a key and value are needed; multiple columns don't make sense, though you could include variable values in another table. In that case, append the column name to the database identifier, separated by a colon; i.e. variable:variable_setting.
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 expireall Expires all catalogs 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.
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.
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
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.
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]
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.
expire -c catalog
There is also an expireall
script which reads all catalog entries in minivend.cfg
and runs expire
on them.
The expire
script accepts a -r
option which tells it to recover lost disk space.
On UNIX, you could add a crontab entry such as the following:
# once a day at 4:40 am 40 4 * * * perl /home/minivend/bin/expireall -r
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.
With Windows or other operating systems which don't fork(),
you will need to stop the server before running expire
-- this will prevent corruption of the database.
If you are not running DBM sessions, you can use a perl script to delete all files not modified in the last one or two days. The following will work if given an argument of your session directory or session files:
#!perl # expire_sessions.pl -- delete files 2 days old or older
my @files; my $dir; foreach $dir (@ARGV) { # just push files on the list if (-f $dir) { push @files, $_; next; }
next unless -d $dir; # get all the file names in the directory opendir DIR, $dir or die "opendir $dir: $!\n"; push @files, ( map { "$dir/$_" } grep(! /^\.\.?$/, readdir DIR) ) ; }
for (@files) { unless (-f $_) { warn "skipping $_, not a file.\n"; next; } next unless -M $_ >= 2; unlink $_ or die "unlink $_: $!\n"; }
It would be run with a command invocation like:
perl expire_sessions.pl /home/you/catalogs/simple/session
You can give it multiple directory names if you have more than one catalog.
You can adjust this script to do what you wish, of course. Refinements might include reading the file to ``eval'' the session reference and expire only customers who are not members.
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 uninitialized variable'' warnings generated by undefined debug references. You can safely ignore these if they occur pointing to lines where the logDebug routine is called.
The controls are accessed in one of several ways.
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.
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]
# UNIX C-shell types (tcsh, csh, etc.) setenv MINIVEND_DEBUG 1279
# UNIX Bourne-shell types (bash, sh, ksh, etc.) MINIVEND_DEBUG=1279 export MINIVEND_DEBUG
# Windows/DOS command box set MINIVEND_DEBUG=1279
minivend.cfg
) and for each catalog (in catalog.cfg
) with the DebugMode directive, with levels as above.
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.
The installation program (makecat) can be used to install your own custom catalog template. See the supplied demo template simple for examples.
There is also, starting with MiniVend 3.11, a ``wizard'' interface that operates completely through HTML.
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.
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.
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:
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.)
Contributions to MiniVend have been made by:
Andreas Koenig Heinz Wittenbecher Birgitt Funk Jochen Wiedmann Bob Jordan Larry Leszczynski Brian Bullen Marc Austin Bruce Albrecht Michael McCune Don Grodecki Tim Baverstock Frank Bonita William Dan Terry Gunnar Hellekson many others
and, of course, the entire Perl team without whom MiniVend could not exist.