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.
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.
Multiple servers can be 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 upfront 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.
MiniVend keeps track of who is ordering what by including in the URL a session id: a random string 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:
An explanation of each part:
Pages are delivered through the following steps:
If you are on a Solaris, or another UNIX which does not have native and complete flock() support, you must also obtain the File::Lock module at the same place that Perl is available from. File::Lock is included in the distribution and will be installed if possible and appropriate. If you have Perl 5.004, you don't need File::Lock.
MiniVend is complex and requires a lot of memory. See the file LOW_MEMORY for ways to reduce memory consumption by up to 30% at some penalty in page loading speed.
You can download the latest Perl 5 from any CPAN (Comprehensive Perl Archive Network) site. Here are some of the many:
NORTH AMERICA
EUROPE
AUSTRALASIA
ASIA
AFRICA
MiniVend uses a server running in the background, with a small C program (generically called vlink ) that communicates with MiniVend via a UNIX-domain socket.
To improve security, MiniVend normally runs with the socket file having 0600 permissions (rw-------), which mandates that the CGI program and the server run as the same user ID. This means that the vlink program must be SUID to the same user ID as the server executes under. (Or that CGIWRAP is used on a single catalog system).
With MiniVend 3.0 multiple catalog capability, the permissions situation gets a bit tricky. MiniVend comes with a program, makecat, which configures catalogs for a multiple catalog system. It should properly set up ownership and permissions for multiple users if run as the superuser.
This will require an Internet connection. Follow the prompts of the CPAN module.
If you can't use the above, obtain, decompress and untar the distribution:
If you have GNU tar, you can combine these steps:
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:
Run the configure script with:
If you have trouble with ./configure, try this:
Replace the 'perl' with the proper path to your Perl 5.003 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 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:
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 users' personal information.
The Catalog directive defines which catalogs will be created at server startup.
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''.
is encountered in the catalog.cfg file.
Check the README file, the FAQ, and mail list archive at the official MiniVend web site for information:
You may subscribe to the MiniVend users mail list by sending the message text subscribe minivend-users to:
Double check that you have the following things:
1. The vlink program is SUID, or you have made appropriate changes in the ReadPermission and WritePermission directives. Unless the files are world-writable, the vlink program and the MiniVend server must run as the same user ID!
If you have trouble with the vlink program (named sample or simple in the demo configurations), try copying the tlink INET mode link program over it. This should work unchanged for many systems, but if you are on an ISP or have a non-standard network configuration you may have to make some changes to minivend.cfg . For tlink to work you must have the proper host name(s) configured into the TcpHost directive in minivend.cfg . The program selects port 7786 by default (the ASCII codes for ``M'' and ``V'') -- if you decide to use another port, you must set the same number in both the tlink program (before compilation, or by editing tlink.pl) and the minivend.cfg file.
The tlink program does not need to be SUID.
2. That you have proper file permissions.
IMPORTANT NOTE: The MiniVend server should not run as the user nobody!
The program files can be owned by anyone, but any databases, ASCII database source files, error logs, and the directory that holds them must be writable by the proper user ID, that is the one that is executing the minivend program. The best way to operate in multi-user, multi-catalog setups is to create a special minivend user, then put that user in the group that each catalog user is in. If you can define a group for each individual user, that provides the best security. Then all associated files can be in 664 or 775 mode, and you should have no problems with permissions.
3. The vlink program is being executed on a machine that has the socket file etc/socket on a directly attached disk. UNIX-domain sockets will not work on NFS-mounted filesystems! That means the server minivend and the CGI program vlink must be executing on the same machine.
The tlink program does not have this problem, but it must have the proper host name(s) and TCP ports set in the TcpHost and TcpPort directives in minivend.cfg . Also, you should be careful of security if sensitive information like customer credit card numbers is being placed on a network wire.
4. MiniVend by default monitors both the UNIX and INET domain sockets that connect to it. If you are only using vlink , the server can be started with the start_unix command -- with tlink, the server is started with start_inet.
If you have a problem you are not able to correct, and you have closely examined the documentation and support resources from front to end, you can submit a problem report to:
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.
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.
Some other things you might put in:
You can also define any other attribute information in a database field.
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 whereever 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 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] element. Individual products can be ordered by the [order <item-code>] element, which brings up the shopping basket page ``basket.html''. The shopping basket page contains 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. By default this is ``confirmation.html'', but any page can be defined as the receipt.
Unless you are using the ``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.
MiniVend has the capability of defining an image directory (with the ImageDir directive) that automatically adjusts your image path to a set base directory. This is often useful for maintaining multiple catalogs, since you can use the same relative path for all images.
As of MiniVend 3.0, there is a powerful static page-building capability in place. 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 .
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]).
Beginning with MiniVend 3.0, there is an experimental page syntax which interprets tags with named arguments, similar to HTML. It has more regular precedence rules -- tags are interpreted in sequential order rather than a set interpolation sequence. (Page serving speed is usually somewhat slower when using the new syntax.) The calling syntax is shown under the normal syntax -- if not specified, it is the same. Some tags (those inside item_list or loop constructs, for example) are not changed.
To use the new page syntax, place one [new] tag at the top of the page. To force old syntax, place one [old] tag at the very top of the page. Further [new] and [old] tags will control syntax in re-evaluated portions of the page (for example, within the [tag]minivend tags[/tag] construct).
See tags.html for an alphabetical reference.
Insert a hyperlink to the specified catalog page pg. For example, [page shirts] will expand into < a href=``http://machine.company.com/cgi-bin/vlink/shirts?WehUkATn;;1''>. The catalog page displayed will come from ``shirts.html'' in the pages directory.
The additional argument will be passed to MiniVend and placed in the {arg} session parameter. This allows programming of a conditional page display based on where the link came from. The argument is then available with the tag [data session arg], or the embedded Perl session variable $Safe{'session'}->{arg}.
A bit of magic occurs if MiniVend has built a static page for the target page. Instead of generating a normal MiniVend-parsed page reference, a static page reference will be inserted.
Same as the page element above, except it specifies an output frame to target if frames are turned on. The name is case-sensitive, and if it doesn't exist a new window will be popped up. This is the same as the [page ...] tag if frames are not activated. For example, [pagetarget shirts main] will expand into a link like <a href=``http://machine.company.com/cgi-bin/vlink/shirts?WehUkATn;;1'' TARGET=``main''>. The catalog page displayed will come from ``shirts.html'' in the pages directory, and be output to the 'main' frame. Be careful, frame names are case-sensitive.
The optional arg is used just as in the page tag.
Inserts a Vend URL in a format to provide a targeted reference for a client-side imagemap. You set up the <AREA> tag with:
If frames are enabled, this will expand to:
If frames are not enabled, this will expand to:
The optional arg is used just as in the page tag.
Like the areatarget element, except it will never yield a frame target.
The optional arg is used just as in the page tag.
TIP: A small efficiency boost in large pages is to just use the </A> tag.
IMPORTANT NOTE: This doesn't turn of frames in your browser! If you let a TARGET tag escape, it will probably cause a new window to be opened, or other types of anomalous operation.
This element is used to give the customer, while browsing, a way to go to the shopping basket page to check on their order. If they haven't ordered anything yet [finish_order] does not appear at all on the displayed page. If they have ordered an item, the element will expand into something like:
If the optional page is supplied, that will be the order page used to finish the order.
This tag is deprecated -- it is suggested that you use the construct:
It will be removed in a future version of MiniVend.
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.
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.
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.
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.
When called with an attribute, the database is consulted and looks for a comma-separated list of attribute options. They take the form:
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:
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:
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.
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 .
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.
Selects from the predefined color schemes and/or backgrounds, and just becomes a <BODY> tag if none are defined. See Controlling Page Appearance.
Selects from the predefined buttonbars, and is stripped if it doesn't exist. See Controlling Page Appearance.
Selects from the predefined rotating banner messages, and is stripped if none exist. The optional ceiling sets the highest number that will be selected -- the default is to sequence through all defined rotating banners. Each user has a separate rotation pattern. See Controlling Page Appearance.
Places an iterative list of the items in the specified shopping cart, the main cart by default. See Item Lists for a description.
The text description of mode -- the default is the shipping mode currently selected.
Formats text in tables. Intended for use in 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.
The parameters are:
will display:
TIP: The [calc] tag is really the same as the [perl] tag, except that it doesn't accept arguments, is more efficient to parse, and is interpolated at a higher precedence.
will display:
Uses the Locale , PriceDivide , and PriceComma settings as appropriate, and can contain a [calc] region. If Locale is set to 'pt', and PriceDivide to 100, the following
the number 1.500,00 will be displayed.
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 [nitems] and [shipping] will reflect the normal price field -- you must either emulate those operations with embedded Perl or the [item-list], [calc], and [currency] tags, or use an embedded Perl routine to set it. This would change the price field used:
Place it at the top of the page, before the [item-list], to ensure it is interpolated early enough.
This facility cannot be considered a language, for constructs cannot be nested in a linear fashion, and operations cannot be performed (except as side effects to the [if] tag).
Starting with MiniVend 3.0, a new tag syntax becomes operational. It overcomes some of the limitations of MiniVend conditional HTML, but is still early.
NOTE: MiniVend interpolates tags in a highly ordered fashion, with each tag having a precedence. The order of the tag interpolation can be changed by enclosing the tag in a set of double square brackets, bringing it forward in the process. The order of interpolation is:
Most of the tests use Perl code, but MiniVend uses the Safe module with its default restrictions to help ensure that improper code will not crash the server or modify the wrong data. There is nothing to be done if your code enters an endless loop, though, and you have to use this capability with caution.
Allows conditional building of HTML based on the setting of various MiniVend session and database values. Accessible areas are:
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:
Key matching is case-insensitive.
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:
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:
The op term is the compare operation to be used. Compare operations are as in Perl:
Any simple perl test can be used, including some limited regex matching (no whitespace or conditionals can be contained in the comparison string). Discussion of this is beyond the scope of this document.
NOTE: This is ignored if using the new syntax.
NOTE: This is ignored if using the new syntax.
NOTE: This is ignored if using the new syntax.
Sets a scratchpad variable to value . One way this is used is to save pages that a customer has seen -- perhaps for a rotating message. A rotating message implementation is shown in the sample page flypage.html .
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.
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 writeable, for example.
Databases will hide variables, so don't name a database ``session'', ``scratch'', or any of the other reserved names! Case is sensitive, so in a pinch you could call the database ``Session'', but it would be better not to.
Returns a string consisting of the value, 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.
Limited to 1024 values in the list in the direct call -- to iterate over a complete database use [tag each database] list text [/tag].
Same thing, except to the file products/new_products.txt:
Same thing, except the export is done with a PIPE delimiter:
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:
mSQL and in-memory databases are always writeable.
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).
The file is relative to the catalog directory, and only may be an absolute path name if NoAbsolute is set to No.
will return
When used in concert with [tag mime boundary], [tag mime header], and [tag mime id], allows MIME attachments to be included -- typically with PGP-encrypted credit card numbers. See the demo page ord/receipt.html for an example.
Where it is useful is in adding long strings that would otherwise be difficult to encode, like
instead of:
&
#lt; and &
#91; respectively.
(new syntax [perl arg=``arguments''])
Using MiniVend variables with embedded Perl capability is not recommended unless you are thoroughly familiar with Perl 5 references. It is best to pass the values you need with MiniVend tags, which are mostly interpolated before the [perl] tags. Example:
This allows you to pass user-space variables for most needed operations. You can pass whole lists of items with constructs like:
Even easier is the definition of a subroutine:
(The escaped causes any single quotes which might be contained in the values to be escaped, preventing syntax errors in the case of a name like ``O'Reilly''.)
The arguments that can be passed are any to all of:
Careful with this -- you can lose the items on order with improper code, though syntax errors will be caught before the code is run.
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.
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.
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:
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:
To show the user their name, and the current time:
Because the tags are the same, an [item_list] cannot be used on an on-the-fly page. The [loop item, item] tag is still usable.
If the directive PageSelectField is set to a valid product database field which contains a valid MiniVend page name (relative to the catalog pages directory, without the .html suffix) it will be used to build the on-the-fly page.
Active tags in their order of interplation:
The names of these pages can be set with the SpecialPage directive. The standard pages and their default locations:
This version of MiniVend implements the database in GDBM, DB_File, Msql, or in-memory format. If you have DBM, large catalogs can be used without using too much memory. The DBM files are built automatically when they change, from the the ASCII source file. If you don't have either GDBM or DB_File, or you set the environment variable MINIVEND_NODBM before starting the server, an in-memory product database will be used. Catalogs of more than, say, 1,000 items will use large amounts of memory.
Support for the mSQL database is included. Form-based updates and inserts allow user input and remote maintenance.
MiniVend reads the data to place in the DBM files from standard ASCII-delimited files. They can have ^M (carriage return) characters if desired, but must have a newline character to work -- Mac users uploading files must use ASCII mode, not binary mode!
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, or use the provided adjexcel utility to correct most of those problems.
Three delimiter schemes are provided as standard:
IMPORTANT NOTE: The items must be separated by a single delimiter character. The items are lined up for your reading convenience.
The Delimiter directive sets the scheme, and should be set to one of those three values. TAB is the default scheme.
IMPORTANT NOTE: Field names are always 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 file . It is kept in the file products.asc in the products directory by default.
It also has a number of standard but optional databases, some of which are in fixed special formats:
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 a 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 -- you will be sorry if you do. Using CSV for non-searchable databases is fine, however.
The databases are specified in Database directives, as:
That specifies a type 4 database, the ASCII version of which is located in the file arbitrary.asc (the DBM file, if any, will go there as well, as arbitrary.db or arbitrary.gdbm), and the identifier it will be accessed under in MiniVend is ``Arbitrary''.
The identifier is case sensitive, and can only contain characters in the class [A-Za-z0-9_]. Fields are accessed with the [item_data name field] or [data name field key] elements.
It is beyond the scope of this document to describe SQL, Minerva, or MsqlPerl, and we will not attempt to. Familiarity is assumed, though the only familiarity with MsqlPerl should be that required to install the module -- MiniVend should do the rest.
MiniVend cannot create the initial mSQL database, but once the database is available via the mSQL server (and is writable or readable by the user ID running the MiniVend server) it can be created from an ASCII file as with any other MiniVend database.
This keeps the default MiniVend definitions for code (char 14 and primary key), price (char 128), and image (also char 128), but sets the description field to a size and type of char(250). Any mSQL type may be used, though if setting the fields with a select statement you must take care of the formatting.
The field delimiter used for the ASCII file is always TAB, and the record delimiter is always newline. If
If you wish to use an existing mSQL database instead of importing, just make sure there is no file with the same name as the database in the ProductDir or DataDir . If you must have a file for searching, it is recommended that you use the mv_search_file variable and make it another name. If you do have a file there, just make sure there is a file in the directory with the same base name and a .sql extension, otherwise an import will be attempted. (In MiniVend 3.0, you may also set the NoImport directive.)
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 Minerva database could be overwritten. In any case, always back up your database before enabling it for use by MiniVend.
(If using the experimental DBI support, substitute 'sql' for 'msql' in all tags below.)
my $string =<<'EOF'; [msql array]select * from arbitrary where code <= '19'[/msql] EOF my $ary = eval $string; my $out = ''; my $i; foreach $i (@$ary) { $out .= $i->[0]; $out .= "
"; } $out; [/perl]
NOTE: The 'EOF' string terminator must START the line, and not have trailing characters. DOS users, beware of carriage returns!
my $string =<<'EOF'; [msql hash]select * from arbitrary where code <= '19'[/msql] EOF my $hash = eval $string; my $out = ''; my $key; foreach $key (keys %$hash) { $out .= $key->{field1}; $out .= "
"; } $out; [/perl]
The values entered by the user are escaped, which prevents errors if quote characters have slipped into their entry.
SKU | Description | Price | [msql list select * from arbitrary where code > '19' order by field2 ]
---|---|---|
[page [msql-code]][msql-code] | [msql-param 1] | [msql-param 2] |
It uses the same tags as in the [loop_list], except prefixed with msql. Available are the following, in order of interpolation:
These special fields all begin with mv_, and include:
(O = order, S = search, C = control, A = all)
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:
And on the form you would make a submit button:
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:
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.
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:
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:
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:
An example would be a password-protected message. Here is a form:
And a subroutine:
This will output CHECKED if the variable var_name is equal to value . Not case sensitive.
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:
Here is the same thing, but for a shopping-basket color selection
To submit a form to the regular non-secure server, just omit the secure modifier.
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:
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.
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.
Examples of search forms and result pages are included in the supplied demos.
Two search engine interfaces are provided, and four 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 . The last is a range-based search, used in combination with one of the above.
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.)
Here is a simple 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:
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:
In the hot-linked URL search:
If you want to let the user decide on the search parameters, you can use checkboxes or radiobox fields to set the fields:
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).
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:
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.
The search must be done on a dictionary-ordered pre-built index, production of which is left as an exercise for the user.
Hint: the field to search is the first field in the file, then the product code should be in the second field, delimited by Delimiter . You will also have to set mv_return_fields=1 to return the product code in the search.
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.
Here is the same thing from a home page (assuming /cgi-bin/vlink is the CGI path for MiniVend's vlink):
The two-letter abbreviations are mapped with these letters:
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, but only
in a scheme like URL decimal encoding, i.e. .32 is a space, .47 is a
/
, etc. -- &sp;
or  
will not be recognized.
To replace a / (slash) in a file name (for the sp parameter) you can use the shorthand of ::, i.e. sp=results::standard.
So if you wish to do an OR search on the fields category and artist for the strings ``Surreal'' and ``Gogh'', while matching substrings, you would do:
and place them in a file. Define the file name in the SearchProfile directive. Re-start the server. The profiles are numbered in the order found (not by file name), starting at 0, and are available by setting the variable mv_profile to the number of the profile. The profile may be named by placing a name following a __NAME__ pragma:
The __NAME__ must begin the line, and be followed by whitespace and then the name. The search profile can then be accessed by mv_profile=``title_search'' .
The special variable mv_last stops interpretation of search variables. The following variables are always interpreted:
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.
The search profiles are also available, and especially useful, for one-click searches. They are available by setting scan/mp=n/se=text, where n is the number of the profile.
If you want to place multiple search profiles in the same file, separate them with __END__, which must be on a line by itself. Be careful, then they are interpreted in the order found, with the second file name not necessarily being the second profile (which would be numbered 1).
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.
-H
option,
and Glimpse will look for its indices there. Default is ProductDir.
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:
.
The order of this and the mv_dict_end variable is significant -- each will overwrite the other.
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].
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.
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).
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 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.
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.
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.
On the search page, some special MiniVend tags are used to format the otherwise standard HTML. Each of the iterative tags is applied to every code returned from the search -- this is normally the product code, but could be a key to any of the arbitrary databases. The value placed by the [item-code] tag is set to whatever the first field (separated by whitespace) is, at least when the default of yes is in the UseCode directive.
In particular, all of the item tags described under order page are active. The most useful one might be [item_link], which if properly used, can allow the user to search the catalog for an item, then click a link to go to detailed catalog page for the item. See the sample results.html page for an example.
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.
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:
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:
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] 2r or <1>.
PERFORMANCE TIP: on heavily trafficed 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.
Use in conjunction with the [more] element to place pointers to additional pages of matches.
If the optional arguments next_img, prev_img, and/or page_img are present, they represent image files that will be inserted instead of the standard 'Next', 'Previous', and page number. If prev_img is none, then no previous link will be output. If page_img is none, then no links to pages of matches will be output. These are URLs, are substituted for with ImageDir , and will be encased in IMG tags.
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.
As an example, if you use [more-list next.gif prev.gif page_num.cgi], the following will be the anchors:
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.
To change this, set the scratch variable mv_put_session on the page in question:
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:
If your catalog frequently specifies category searches in a large catalog, speed of search return can be increased by a large factor.
You needn't do more than just enable the cache for one-click searches. To make them operate on a form-based search, specify the form variable names, separated by a spaces and/or a comma, that will generate a unique cache key. Example:
If you have the MD5 module installed on Perl, it will be used to generate the cache keys. This will guarantee a unique cache ID.
If you don't have MD5 installed, a 32-bit checksum will be used to create the cache key. It is conceivable, but unlikely, that two separate searches could generate the same 32-bit checksum and return the same cached search.
IMPORTANT NOTE: The search cache is only invalidated by a catalog reconfiguration. If you change your product database or any other files you search, you should reconfigure or the search returns may be wrong.
Search caching is disabled on a client-by-client basis if the client browser does not have cookie capability, for the generated session numbers would be incorrect otherwise.
The name of the page to display can be configured in several ways:
The structure of the Accessories database is a simple key-value pair -- if you have more complex accessory setups you can define one of the Arbitrary Databases and use that.
The following elements are used on the order page:
COMPATIBILITY NOTE: MiniVend 1.02 used the [/if] end tag for an [if_field] element. This was supported through MiniVend 1.03, but is gone in 2.0 -- you may need to change it.
n
(from the products file)
of the current item.
n
(from the products file)
of the current item. Returns regular price if not discounted.
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:
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:
An item subtotal:
A cart subtotal, using the item-list tag:
The zero is needed because of the trailing plus sign left by the iterative [item-list] tag.
Even sales tax can be emulated if you use something like a [data salestax [value state]] tag, and do some similar calculation. That is left as an exercise for the user.
Shipping and the [nitems] tag will still work properly with a different price.
You can also order items from a form, using the mv_order_item, mv_cartname , and optional mv_order_quantity variables.
Specifications take the form of an order page variable (like name or address), followed by an equals sign and one of five check types:
The following file specifies a simple check of formatted parameters:
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. Be careful, then they are interpreted in the order found, with the second file name not necessarily being the second profile. (Which would be numbered 1, of course, just for clarity. At least it is clear to a programmer.)
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 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>.
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.
Choose a name for this input field such as ``email'' for an email address. Set the name attribute to the name you have chosen.
The value attribute specifies the default value to give the field when the page is displayed. Because the customer may enter information on the order page, return to browsing, and come back to the order page, you want the default value to be what was entered the first time. This is done with the [value] element, which returns the last value of an input field. Thus,
will evaluate to the name entered on the previous order screen, such as:
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.
For speed, MiniVend builds the code that is used to determine a product's price at catalog configuration time. If you choose to change a directive that affects product pricing you must reconfigure the catalog.
There are several ways that MiniVend can modify the price of a product during normal catalog operation. Several of them require that the pricing.asc file be present, and that you define a pricing database. You do that by placing the following directive in catalog.cfg :
Configurable directives and tags with regard to pricing:
To enable the automatic modifier handling of MiniVend 3.0, you would define a size field in products.asc:
You would place the proper tag within your [item-list] on the shopping-basket or order page:
In the pricing.asc database source, you would need:
The configuration file directive UseModifier is used to set the name of the modifier or modifiers. For example
will attach both a size and color attribute to each item code that is ordered.
As of MiniVend 2.02, setting the mv_separate_items or global directive SeparateItems places each ordered item on a separate line, simplifying attribute handling.
The modifier value is accessed in the [item-list] loop with the [item-modifier attribute] tag, and form input fields are placed with the [modifier-name attribute] tag. This is similar to the way that quantity is handled, except that attributes can be ``stacked'' by setting multiple values in an input form.
You cannot define a modifier name of code or quantity, as they are already used. You must be sure that no fields in your forms have digits appended to their names if the variable is the same name as the attribute name you select, as the [modifier-name size] variables will be placed in the user session as the form variables size0, size1, size2, etc.
You can use the [loop item,item,item] list to reference multiple display or selection fields for modifiers (in MiniVend 3.0, you can have it automatically generated --see below). The modifier value can then be used to select data from an arbitrary database for attribute selection and display.
Below is a fragment from a shopping basket display form which shows a selectable size with ``sticky'' setting. Note that this would always be contained within the [item_list] [/item-list] pair.
It could just as easily be done with a radiobutton group combined with the [checked ...] tag.
MiniVend 3.0 will automatically generate the above select box when the [accessories size <code>] or [item-accessories size] tags are called. They have the syntax:
When called with an attribute, the database is consulted and looks for a comma-separated list of attribute options. They take the form:
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:
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:
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].
The discounts are specified via a formula. The formula is scanned for the variables $q and $s, which are substituted for with the item quantity and subtotal respectively. In the case of the item and all items discount, the formula must evaluate to a new subtotal for all items of that code that are ordered. The discount for the entire order is applied to the entire order, and would normally be a monetary amount to subtract or a flat percentage discount.
Discounts are applied to the effective price of the product, including any quantity discounts.
To apply a straight 20% discount to all items:
To take 25% off of only item 00-342:
To subtract $5.00 from the customer's order:
Perl code can be used to apply the discounts. Here is an example of a discount for item code 00-343 which prices the second one ordered at 1 cent:
If you want to display the discount amount, use the [calc] capability. This example calculates the amount of the discount for all items in the current shopping cart:
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:
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.
To use CyberCash, you must first have a CyberCash Secure Merchant Payment Server (SMPS) running on your system. It must be fully enabled, and should be tested OK with the CyberCash test suite. This capability has been tested to work with SMPS-2.1.x in 'mauthcapture' mode.
The CCLib.pm file must be available to MiniVend -- if you cannot install it in the main Perl library then the Minivend software directory lib/ will suffice.
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:
the default mode of mauthcapture will be selected. But it must be defined on the submitting form, and not on a previous form.
The order mode must be final, either by omitting an order profile entirely or by defining an order profile that contains &final=yes.
If you must use other values, they can be redefined in catalog.cfg with the Variable CYBER_REMAP like so:
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.
To enable custom shipping, enter the default field to use in the CustomShipping directive:
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.
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:
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 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:
NOTE: You may use the same mode name for all lines in the same group, but the first one will contain the main criteria.
NOTE: The columns are lined up for your reading convenience, the actual entries should have ONE tab between fields.
If the cost returned is zero, the reason will be placed as an error message in the session variable ship_message (available as [data session ship_message]).
UPS weights are always rounded up if any fraction is present.
The routines use standard UPS lookup tables. First, the UPS Zone file must be present. That is a standard UPS document, specific to your area, that you must obtain from UPS and enter into and make available to MiniVend in TAB-delimited format. (As of March 1997, you can use the standard .csv file distributed by UPS on their web site at www.ups.com.) You specify it with the UpsZoneFile directive -- it is usually named something like NNN.csv, where NNN is the first three digits of the originating zip code.
Second, you must obtain the cost tables from UPS (again, you can get them from www.ups.com) and place them into a MiniVend database. That database, its identifier specified with the first argument (upsg in the example) of the cost specification, is consulted to determine the UPS cost for that weight and rate schedule. See the sample demo for an implementation.
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:
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.
Sub <<EOF 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
The parameters are interpreted for MiniVend tags before being parsed. Here is a complete example:
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:
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).
If you wished only to process a handling charge once, you could do safely:
A non-blank/non-zero value in the database field very_heavy will then trigger Perl code which will only set mv_handling once.
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.
IMPORTANT NOTE: MiniVend attempts to perform operations securely, but no guarantees or warranties of any kind are made! Since MiniVend comes with Perl source, it is possible to modify the program to create bad security problems. One way to minimize this possibility is to record digital signatures, using MD5 or PGP, of minivend, minivend.cfg , and all modules included in minivend. Check them on a regular basis to ensure they have not been changed.
MiniVend uses the SecureURL directive to set the base URL for secure transactions, and the VendURL directive for normal non-secure transactions. Secure URLs can be enabled for forms through the [process_target action secure] element.
MiniVend incorporates additional security for credit card numbers. Any field on the order form which has credit_card in its name will not be written to disk unless it is encrypted. An external encryption program, such as pgp(1) or des(1) can be used.
NOTE: The internal Des encryption mode is no longer supported in MiniVend 2.02 and higher. Try PGP instead -- it is more secure and easier to use.
To accept credit_card fields, you need to define the directive CreditCardAuto to yes. EncryptProgram also needs to be defined with some value, one which will, with hope, encrypt the number. PGP is now recommended above all other encryption program. The entries should look something like:
See CreditCardAuto for more information on how to set the form variables.
In addition, you can create a file in any MiniVend page subdirectory called .access. If that file is present and non-zero in size, any pages in that directory are only available to users who have the REMOTE_USER CGI variable set (which means they have given a username and password, ala normal HTTP Basic Authorization). This is a way to provide ``subscription-only'' pages that are only available to logged-in users.
Frames are accessed by adding a TARGET element to a HREF, naming the frame that the referenced URL should be placed in. MiniVend produces targets with the pagetarget and areatarget elements, which send target tags if frames are enabled (by a [frames_on] element. Any frame name can be used, including the special frames of _top, _blank, _parent, and _self.
As shown in the demo pages, the best way to accommodate both types of browsers is by having an index.html page that sets the beginning frame set. The <FRAMESET> and <FRAME> tags will be ignored by standard browsers, which will read the HTML between the <NOFRAMES> and </NOFRAMES> tags below.
The format of the first set of URLs passed to the frames is important - only ONE MiniVend link must be called. That sets the session ID for the user. If two URLs were called, MiniVend would assign two session IDs to the user, scrambling the context of their navigation. From this single access, all further references to MiniVend are made, though after the first access multiple frame targets can be referenced.
This first MiniVend page that is accessed (with a frame browser) should contain a [frames_on] element. It is the only page that need (or should) contain a [frames_on], which is persistent throughout the session. This page should never be seen by a non-frame browser.
Subsequent accesses to MiniVend URLs will now contain the proper session information, and as long as pagetarget or page elements are used to pass the URLs, context will be maintained.
The [pagetarget page frame] element is used to pass target tags in hyperlinks. The [areatarget page frame] element is used to pass target tags in imagemaps. The [frames_on] and [frames_off] elements enable and disable frame operation. The [framebase frame] element sets a base target for a page.
See the sample demo pages:
You can use One-click Multiple Variables to set the target if you wish.
The above snippet will, when placed in a MiniVend form, send the output of a Search submission to the current default frame, but when Continue Shopping is selected the output will will go to the page browse.html with the page routed to the top level frame for the current browser window.
If you are setting a target with the [process_target target] tag, you will either have to make that target none or set the scratch variable mv_ignore_frame on the page at time of display. Either will prevent conflicting window targets from being sent.
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:
The above sequence set in the catalog.cfg file, defines three color schemes, accessed with [body 1], [body 2], and [body 3] elements in MiniVend pages. The first scheme uses the file /images/blue_pap.gif as the background pattern, and keeps the user's default colors for everything else. It is called by a [body 1] element, which when expanded becomes <BODY BACKGROUND="/images/blue_pap.gif>.
The second scheme defines no background pattern (there is only one file in the Mv_Background directive), but defines a background color of 'steelblue', with a text color of white, a link color of light green, and a visited link color of orange. It is accessed by the [body 2] element, which when expanded becomes <BODY BGCOLOR=``steelblue'' TEXT=``white'' LINK=``ltgreen'' VLINK=``orange''>.
The third color scheme is similar to the second, except defines white-black-blue-purple for the four colors. It is accessed with a [body 3] element.
If there is no defined scheme for a body element (as there wouldn't be if you put [body 4] in a page with the above schemes defined) MiniVend simply outputs a standard <BODY> tag.
The user can also define their own colors if the Mv_customcolors variable is set (upon a form submission). See the supplied control.html page for an example of how to set custom colors.
Image maps can be supplied and similarly controlled with the [buttonbar n] series of tags. They are defined with the ButtonBars directive in catalog.cfg, and take the form of a series of file names in MiniVend format -- i.e., relative to the PageDir and without a .html extension. To use the buttonbars, create a file with an IMG directive set with the USEMAP element and an associated client-side image map (defined with <MAP> </MAP>. The [areatarget] or [area] tags are used to set the URLs. An example:
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:
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.)
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:
You can also use it to build page trees that are scannable by a search engine spider.
It is invoked when starting the MiniVend server by passing the extra parameters -build shop to the start or restart command. 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.
Tags which cause static building to fail are:
In addition, if a [search_list] references dynamic items, it will also prevent a search from being cached or built statically.
Pages are also searched for static [page scan/...] searches, and those searches are built statically if appropriate. They are placed in the pages scan1.html on up, so don't name any of your pages scan and then digits if you want to avoid clashing.
A page marked as an AdminPage will not be statically built or cached.
Pages are marked for static build in one of two ways:
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.
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 pages that are present will be overwritten!
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:
where shop is the name of the catalog to be built. (Multiple -build name directives can be used to build more than one catalog.)
TIP: StaticFly only builds products from the first products database. If you are using multiple ProductFiles, you can build for all in turn by selectively changing the ProductFiles directive temporarily while building off line.
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.
If no Catalog directives are present, all of the directives listed under Catalog Configuration File are operative for the single catalog that will be served by MiniVend.
Otherwise, there are only a few directives that are defined in the minivend.cfg file.
The first is the name of the catalog -- it will be referred to as that name in error, warning, and informational messages.
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.
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 exectable 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.
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.
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.
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.
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.
Actions are overwritten, even the default ones, if re-defined. Default is blank. Can be set as many times as necessary. Not case sensitive.
The choices to enter are:
Enter as a space or comma-separated list, i.e.
Orders are typically logged to other files via AsciiTrack, AsciiBackend, or the [tag log ...]data[/tag] construct.
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.
It must have at least two periods or browsers will ignore it.
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.
As of MiniVend 3.0, the products databases are the same as arbitrary databases, differing only by their identification in the ProductFiles directive. The default value is ``products products.asc 1'', which sets up the products database by default. The location of the products file may be changed by re-defining the database identifier products .
Default is 'description'. It is no longer a fatal error if this field does not exist.
Overrridden 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.
If the file (or the entry) 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). See the demo for an example of how it is used.
Example of the custom setting:
Example of POSIX setlocale for France, if properly aliased:
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.
The default prevents clashes with embedded Perl code.
They are accessed by setting the mv_order_profile variable to the number of the order profile, starting at 0. Multiple profiles can reside in the same file, if separated by __END__ tokens, which must be on a line by themselves.
The profile may be named by placing a name following a __NAME__ pragma:
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'' .
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'.
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.
A common case would be size. For shirts that are size XXL, you might wish to add a dollar to the price for an item. In that case, you can define a column in the standard pricing database 'pricing' which is named ``XXL''. If a value is found in that column it will be added to the price for the item. Negative numbers result in subtraction if you wish to reduce the price based on an attribute.
See CommonAdjust for another scheme that makes the same adjustment for any item having the attribute -- both schemes cannot be used at the same time. (This is true even if you were to change the value of $Vend::Cfg->{CommonAdjust} in a subroutine -- the pricing algorithm is built at catalog startup.)
As an added measure of control, the specification is evaluated with the special MiniVend [if area value ....]value[else]other value[/else][/if] syntax to provide conditional setting of search parameters.
The following file specifies a dictionary-based search in the file 'dict.product':
The search profiles are specified in the same manner as the ButtonBars directive, with files to be located in the MiniVend page tree and read at program startup. If you change a search profile, you must stop and start MiniVend to have the changes take effect.
They are accessed by setting the mv_profile variable to the number of the search profile, starting at 0. Multiple profiles can reside in the same file, if separated by __END__ tokens, which must be on a line by themselves.
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.
Can be overridden with the mv_separate_items variables (both scratch and user).
It is possible for multiple catalogs to share the same session file. This allows a ``mall'' to be set up where many storefronts 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.
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.
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:
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
and calling the routine with
is the same as calling
This can make calling routines more natural, and is especially useful in combination with mv_subroutine .
Most users now use the simpler and more flexible Easy ASCII Tracking capability.
See the sample demo for an implementation -- the zone file in use
is for Denver, CO and environs.
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):
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:
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:
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:
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.
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.
The following updates the products database price field for item 19-202 with the new value 25.00
More than one field can be updated on a single command line
The following takes input from file , which must be formatted exactly like the original database and adds/corrects any records contained therein.
Invoke the command without any arguments for a usage message describing the options.
You could add a crontab entry such as the following:
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.
The installation program (makecat) can be used to install your own custom catalog template. See the supplied demo template directories ``sample'' and ``simple'' for examples.
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 full-featured demo:
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/sample, and file paths that are complete fully-qualified file path names.
To install the simple demo:
You will see some output as the configure script checks your system. Then compile the programs:
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.
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 unnecessary security risk. It should also not normally run as the default WWW user (often nobody)).
Move the vlink executable to your cgi-bin directory:
Make vlink setuid:
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.)