Table of Contents
List of Tables
The Address Verification System (AVS) is used to check the likeliness that the customer claiming to own the credit card is the real owner.
Interchange allows you to create "virtual pages" by associating code (such as Perl subroutines or ITL tags) with parts of an URL. This can be used for anything from implementing one-click searches and orders to displaying on-the-fly data.
On every catalog access, the leading part of a requested URL is taken and checked if it represents a valid action. If it does, the action is invoked with the rest of the arguments provided in the URL.
Some of the predefined actions (which you might recognize from special page names that you access in your catalog) are:
process - Generic form processing function
order - Order items
scan - Search based on submitted URL
search - Search based on submitted form variables
A rectangular graphic image which is included on a content page for advertising and promotional purposes.
In Interchange, when "banner" or "ad" is used to describe the functionality of
the banner tag and it does not necessarily mean an image, as you can
put anything in the content placeholder. In fact, banner examples from
???? HOW-TO use plain
text.
Voluntary ad unit guidelines as suggested by the Interactive Advertising Bureau (specified in pixels, in ascending order):
Micro Bar - 88x31
Button 2 - 120x60
Button 1 - 120x90
Half Banner - 234x60
Square Button - 125x125
Full Banner - 468x60
Vertical Banner - 120x240
Rectangle - 180x150
Medium Rectangle - 300x250
Vertical Rectangle - 240x400
Square Pop-up - 250x250
Large Rectangle - 336x280
Skyscraper - 120x600
Wide Skyscraper - 160x600
You can see the above dimensions in practice at MOTIVE Resources.
When giving links to your website to your partners, often times you want to embed an identification string that will link visits or eventual sales to the corresponding partner.
Interchange supports affiliate tracking; the source of the visit or order
is always accessible using [data session source].
So when giving links to your affiliates, make sure the affiliate code you assign them is embedded in one of the following ways:
http://myhost.mydomain.local/cgi-bin/standard/index?;;thesource (old Minivend 3 way, still works) http://myhost.mydomain.local/cgi-bin/standard/index?mv_pc=thesource (Interchange way, still works) http://myhost.mydomain.local/cgi-bin/standard/index?mv_source=thesource (current way)
Note that mv_source was added as an affiliate code-passing option
only in Interchange 4.9.x. Before that, affiliate code was passed in mv_pc.
The mv_pc variable is used as a variable containing a random number
to prevent caching of pages. So if you want to use mv_pc as a way of
carrying over the affiliate code, it must contain at least one non-digit.
(mv_pc=A12 is a good affiliate code,
mv_pc=12 is not). If using mv_source, affiliate
code is free of this restriction.
Sometimes you want the affiliate code to disappear from the URL after
the visitors get redirected to your page. To enable that feature, see
BounceReferrals configuration directive.
In general terms, "array" can be considered a synonym for "list". It implies a list of elements.
In the Perl programming language, "list" refers to an unnamed list of any kind, while "array" refers to a practical, named Perl variable of list type.
Attributes (sometimes also called modifiers, options or params) are various "sub-features" of a product. If you are selling t-shirts in different colors and sizes, color and size are ideal candidates for item attributes. Interchange allows attributes to be set for each ordered item. This allows a varying size, color, or any other modifier to be attached to an otherwise common part number.
See UseModifier for more information and concrete examples.
Besides setting modifier names in the config files (via the above
UseModifier), you can also set them as
scratch variables with mv_UseModifier. For example,
the above modifiers would be set with
[set mv_UseModifier]size color[/set].
This effectively allows you to have different product options for different
or even same product SKUs. Those specified in mv_UseModifier at
the time of order will be used (just be careful, because you cannot set it
more than once on the same page).
![]() | Note |
|---|---|
When choosing modifier names, do not use anything that begins with
You also need to make sure that no fields in your HTML
forms have digits appended to their names, if their non-digit name part
is equal to any used attribute. (This is because Interchange treats
say, |
In addition, setting SeparateItems or mv_separate_items
places each ordered item on a separate line even if they have the same
SKU, simplifying attribute handling.
The modifier value is accessed in the item_list loop with the
[item-modifier tag,
and form input fields are created with
attribute_name][modifier-name .
This is similar to the way that quantity
is handled, except that attributes can be "stacked" by setting multiple
values in an input form (whereas there can be only one quantity field
for each item).
attribute]
When you want to provide a series of modifiers for an element,
you can use the standard loop tag (such as
[loop arg="),
or you can use the built-in item item item"]PREFIX-accessories tag available with
most Interchange list operations.
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 the example
can only work within the item_list tag.
<select name="[modifier-name size]"> <option [selected [modifier-name size] S] /> S <option [selected [modifier-name size] M] /> M <option [selected [modifier-name size] L] /> L <option [selected [modifier-name size] XL] /> XL </select>
It could just as easily be done with a radio button group as well (when you combine them with the <checked> HTML tag).
In addition, Interchange would automatically generate the above select box
if you called [accessories
or code size][item-accessories size].
A boolean variable is one that can only represent a true or false value.
The variable type was named after George Boole.
Note that, in Interchange configuration directives parlance,
boolean is used somewhat awkwardly. Instead of adhering
to above definition of boolean, it actually signifies
an array in which you can search for the presence or absence of
a value. Real boolean variables are called yesnos in
Interchange.
This naming confusion is unfortunate, but is fortunately quarantined to the configuration directives "space".
The HTTP (Web) protocol does not use the same mechanism to send data from server to client, and from client to server. Client to server communication must usually happen over CGI (Common Gateway Interface), by having users submit HTML forms.
Form data submitted usually consists of
pairs. One other option are just values following one another
(key=value); those are called
"ISINDEX" queries, and are not generally used with Interchange.
value1+value2+value3...
Form submission can happen in two ways.
The "GET" method is very basic, as it
just embeds form values in the URL being sent to the server. One example of
a GET query is
http://myhost.mydomain.local/cgi-bin/ic/test?mv_arg=1&mv_pc=14.
I think it's simple enough to notice variables mv_arg and
mv_pc being submitted. The GET method is very convenient
because all data is embedded in the URL, making it very easy to copy and
share links with other people.
The other method is called POST. This way, the information is sent in a way not visible to the user. POST forms have this disadvantage of not being suitable for copy-pasting HTML links directly, but they do offer greater flexibility, especially if a lot of form data is being sent.
When forms are submitted using the POST method, they can also embed data
in the URL, effectively passing both POST and GET data at once. Interchange ignores
GET data on POST forms, but can be instructed to parse both using the
TolerateGet directive.
In the end, it turns out you can just use GET in most situations. It's simpler, more convenient, and gets the job done just as well.
CGI variables in Interchange are accessible using the cgi tag, and
only on a page directly following the form
submission. This is logical, of course. A page request reaches the Interchange daemon,
and it either has or doesn't have the accompanying form data; there's no
"history" mechanism included. (However, Interchange does allow you to save values
for future reference, usually in the value or scratch space).
Interchange is, by default, eager to collect user information, at least for the
duration of the session (so the users don't have to retype it again).
During processing, CGI variables are therefore propagated to the values
space, for subsequent requests. The FormIgnore directive specifies
which CGI variables should not be propagated.
Users have complete control over CGI data they will send. Therefore, this input should never be trusted. It's raw data, and it is a security risk to save it in a database or display in a page before sanitization. The most common security risk is displaying HTML code which allows remote scripting exploits like cookie-stealing.
Never do something like the following:
[cgi VARNAME]
or
[calc]
my $out = $CGI->{VARNAME};
return $out;
[/calc]
Fortunately, Interchange offers a number of ways to take care of the data, usually by filtering it. For more discussion and help on filtering, see the filter glossary entry. A safe no-brainer approach is to just use the <filter>encode_entities</filter> filter on the input.
So, to obtain a "safe" value while keeping the original intact, use:
[cgi name=VARNAME filter=entities]
or:
[filter entities][cgi VARNAME][/filter]
or:
[calc]
my $out = $Tag->cgi({ name => 'VARNAME', filter => 'entities' });
return $out;
[/calc]
or:
[calc]
my $out = $Tag->filter($CGI->VARNAME, 'entities');
return $out;
[/calc]
One interesting feature in Interchange is that you can set CGI values yourself.
This has two common uses. You can set a value and pretend as
if it was sent by the user (so the rest of your code doesn't need to split
in two execution paths, depending on whether the variable was set or not).
Another thing you can do, is set special CGI variables (the
mv_* ones that affect how Interchange processes the page) and let
Interchange do its magic. Heck, not only you can set them once, but you can change
their value during processing, achieving different
behavior in different parts of the page.
You can set values by providing
set= attributes
to the VALUE hide=1cgi tag, or by simple assignment in Perl
($CGI->{).
VARNAME} = 'VALUE'
Here's a complete list of ways to access CGI variables:
In ITL:
| Access syntax | Notes |
|---|---|
[cgi VARNAME] | Doesn't prevent users from injecting ITL code; don't use it! |
[cgi name=VARNAME filter=entities] | A safe and correct way to go |
In embedded Perl:
| Access syntax | Notes |
|---|---|
$CGI->{VARNAME} | Retrieves raw CGI value; don't use before filtering |
$Tag->cgi({ name => 'VARNAME', filter => 'entities' }); | A safe and correct way to go |
$Tag->filter($CGI->{VARNAME}, 'entities'); | A safe and correct way to go |
A catalog is the basic functional unit in Interchange. A catalog is to Interchange what a web site is to a Web server.
Catalogs to configure and offer on the Interchange server are defined in the
global configuration file, interchange.cfg (or some of the files it includes, of course,
depending on the actual file layout). The definition directive is called
Catalog. The directive you should use to register a catalog is
— incidentally — Catalog.
Each catalog directory (specified as one of Catalog parameters) must
have the file catalog.cfg in it. For the mandatory directives that need to be
present in the file, see Catalog reference page.
For the general syntax accepted in configuration files, see configuration glossary entry.
For the list of available configuration directives, see Interchange Reference Pages: Configuration directives.
The check-out process consists of users filling in information via HTML forms, and Interchange verifying their input on arbitrary number of levels using so-called profiles.
Profiles can be defined in external files (and activated using
OrderProfile) or in scratch variables. External files are,
by convention, kept in CATROOT/etc/ and
begin with profiles.. Multiple profiles
can be defined in each file.
You can learn about the principle and syntax of the profile files in the profile glossary entry. Only when the input "passes" the profile check, is the check-out process able to proceed.
Most of the time, you will want the successful check-out operation (order completion) to generate some kind of notification. In most common setups, this will include e-mailing order reports.
Simple order report file, CATROOT/etc/report, defines
the layout (template) of the order report. All form variables are accessible
from the report file by using the familiar Perl $ syntax.
Order Date: $date
Name: $name
Email address: $email
Shipping address: $addr
Town, State, Zip: $town, $state $zip
Country: $country
You can specify fully-configurable order reports by setting the hidden
form variable mv_order_report to an existing Interchange catalog page.
This page will be processed (interpolated and all) as standard Interchange
page before being sent by email. That said,
you see you could include HTML in the file. Although many mail clients
will parse HTML, it seems that the initial excitement
among the ordinary people vanished and they
again prefer plain-text e-mails. If you wanted to provide a HTML
version, you could always provide a link to a copy on your web server.
An order counter can be enabled simply — just set the OrderCounter
directive to the appropriate file name.
An incrementing count of all orders will be
kept and assigned as orders are placed. By default, the number
starts at 0, but you can edit the file and change the
starting or current number at any time.
This feature is made possible by the File::CounterFile
Perl module.
The default basket and order pages contain a number of form fields,
allowing customers to enter the necessary information. This, however, can't
satisfy all individual needs. To remove some of the fields, simply delete
them from the HTML pages (or, better yet, disable by using the
comment tag). Do not forget to also deactivate any entries in
the profile files.
To add new fields, simply add them to the pages. The information will
automatically be included in the report files. Here's a template you
could re-use for your own fields, replacing town
with your values:
<input type="text" name="town" value="[value town]" size="30" maxlen="40" />
![]() | Note |
|---|---|
Using |
Interchange supports multiple catalogs, and therefore splits its configuration
into two pieces. One is global, specified in interchange.cfg, and affects every
catalog running under the same Interchange server installation.
The other — catalog part, is specified in each catalog's
CATROOT/catalog.cfg, and has no effect on other catalogs.
Each configuration directive is accessible on global or catalog level,
or both. There's a special field named "DIRECTIVE TYPE"
present in each directive's reference page, where you can look this up.
Keep in mind, however, that the directives on
global and catalog level don't have to be parsed by the same code —
in fact, they're mostly parsed by related but different code blocks.
Configuration directives are normally specified with the directive name as the first word on the line, with its value or values following. Capitalization of the directive name is not significant, but it helps readability and consistency. Additionally, any leading and trailing whitespace is removed ("stripped") before processing. Here's a simple example:
DirectiveNamevalue
Besides specifying directive values inline, one can conveniently use the following syntax to obtain value from external files:
DirectiveName<include_filename
![]() | Note |
|---|---|
Note that this syntax can be used anywhere on a line, such as in
|
Files included from interchange.cfg are relative to ICROOT. Files included
from catalog.cfg are relative to specific catalog's CATROOT.
So-called "here document" syntax is supported as well. You can use it to spread directive values over several lines, with the usual Perl <<MARKER syntax (but unlike Perl, Interchange syntax uses no semicolon to terminate the marker). The closing marker must be the only thing on the line. No leading or trailing characters are allowed, not even whitespace. Here is a hypothetical directive using a here document:
DirectiveName<<EODsetting1 setting2 setting3EOD
The above is equivalent to:
DirectiveNamesetting1 setting2 setting3
Other configuration files can also be included from the current one. For example, common settings can be defined in a single file:
include common.cfg
Or all files loaded from a directory:
include usertag/*
The familiar ifdef/endif and ifndef/endif
pairs can be used to affect configuration processing:
Variable ORDERS_TO email_address ifdef ORDERS_TO ParseVariables Yes MailOrderTo __ORDERS_TO__ ParseVariables No endif ifdef ORDERS_TO =~ /\@foo\.com$/ # Send all orders at foo.com to one place now # Set ORDERS_TO to stop default setting Variable ORDERS_TO 1 MailOrderTo orders@foo.com endif ifdef ORDERS_TO eq 'nobody@nowhere.com' # Better change to something else, set ORDERS_TO to stop default Variable ORDERS_TO 1 MailOrderTo someone@somewhere.com endif ifndef ORDERS_TO #Needs to go somewhere.... MailOrderTo webmaster@mydomain.local endif
It is possible to define configuration directives for the duration
of the block, using the < notation:
DIRECTIVE VALUE> ... </DIRECTIVE>
Variable HELLO Hello World! ParseVariables No Message Our greeting is: __HELLO__ # Will print: Our greeting is: __HELLO__ <ParseVariables Yes> Message Our greeting is the shiny __HELLO__ # Will print: Our greeting is the shiny Hello World! </ParseVariables> Message Our greeting is back to: __HELLO__ # Will print: Our greeting is back to: __HELLO__
Interchange, of course, offers a way to define variables. Variables defined
in your interchange.cfg or catalog.cfg can be referenced from both configuration files
themselves and the usual Interchange pages later, when the catalog is running.
Variables are defined using the Variable directive (reading its
short reference now would be a good idea). The usual way to expand
a variable to it's value is to use the
__ notation.
This notation, however, is by default not enabled in RHS
("Right-Hand Side") values in configuration files. To enable it, use the
VARIABLE_NAME__ParseVariables directive which immediately affects the way
Interchange parses variables in config files. Here's an example to clarify
what we're talking about:
# Let's define two variables Variable SERVER_NAME myhost.mydomain.local Variable CGI_URL /cgi-bin/ic/tutorial # Let's make VendURL directive be a combination of __SERVER_NAME__ and __CGI_URL__ VendURL http://__SERVER_NAME____CGI_URL__ # To your surprise, after the above, VendURL would literally contain # "http://__SERVER_NAME____CGI_URL__". This is not what we want, so # we need to enable ParseVariables to achieve the desired effect: ParseVariables Yes VendURL http://__SERVER_NAME____CGI_URL__ ParseVariables No # VendURL now contains "http://myhost.mydomain.local/cgi-bin/ic/tutorial"
It may come to you as a surprise, to learn that any configuration directive
can be "tied" to a Perl subroutine (if the Tie::Watch
Perl module is installed). This allows for a kind of triggers, watch points,
or numerous other interesting applications.
Similar to "here documents" ("<<"), subroutine watches
are defined using the "<&" notation. Consider the
following example:
MailOrderTo orders@myhost.mydomain.local
MailOrderTo <&EOF
sub {
my($self, $default) = @_;
if($Values->{special_handling}) {
return 'vip@myhost.mydomain.local';
}
else {
return $default;
}
}
EOF
When Interchange tries to retrieve the value of the MailOrderTo configuration
directive (usually to e-mail out an order), our subroutine watch is called. In
turn, it returns a special value (a separate e-mail address) for customers
having value "special_handling" defined in their
session. For the rest, it simply returns the default value.
Now that you've grasped the basics, there's more to the story.
From the above example, you see our watch subroutine was called in style
of &{$subref}(.
"SELF,
PREVIOUS_VALUE)SELF", meaning what it usually means in
Perl code, is a reference to the appropriate Tie::Watch
object. "PREVIOUS_VALUE" is simply the previously
set value for a directive (usually its default). Those are the standard
two arguments we receive in a subroutine watch if the configuration directive
was of type SCALAR (defined to accept one string or text value).
![]() | Note |
|---|---|
Subroutine watches must be defined after the configuration directives have been set to their values. Setting values after subroutine watches will simply destroy them (the watches) and have unpredictable effects. |
If the configuration directive being watched was a list (type ARRAY), the
subroutine would be called in pattern
&{$subref}(.
("SELF,
INDEX,
PREVIOUS_VALUE)INDEX" would be an array index of the
item accessed). Setting watch points on arrays that you don't control
completely is not recommended. (Namely, most Interchange subroutines call arrays
in their list context, and no access method is provided for that).
Finally, if the configuration directive watched was a hash (type HASH),
the subroutine would be called in pattern
&{$subref}(.
("SELF,
KEY,
PREVIOUS_VALUE)KEY" would be a name of the
hash value accessed).
In the following example, we tie the Variable configuration directive.
This is not recommended for performance reasons — Variable
directive is called very often and should not bear any extra overhead). But
it illustrates the power of this operation:
Variable TESTIT Unwatch worked.
Variable <&EOV
sub {
my ($self, $key, $orig) = @_;
if($key eq 'TESTIT') {
# only the first time
if($Scratch->{$key}++) {
$self->Unwatch();
return $orig->{TESTIT};
}
else {
return "Tie::Watch works! -- name=$Values->{fname}";
}
}
else {
return $orig->{$key};
}
}
EOV
The first time __TESTIT__ is called for an individual user,
it would return the string "Tie::Watch works! -- name="
along with their first name (if they provided one at some point).
On a second access (again, for an individual user),
the watch would be dynamically dropped and the default value of the
variable NAMETESTIT returned.
All other variables would operate as usual.
Cookies are typically short
parts supported by the HTTP protocol. Their importance is in the fact that
the server can send them to clients, and read and modify their value.
In addition, cookies have their expiry time, which can be set, also by the
server, to any intended value.
Whether Interchange will try to land session cookies in clients' browsers is
determined by the key/valueCookies directive, and their default expiry time
is set by SaveExpire.
Clients can control whether they reject or accept cookies from all or some sites, and can enforce their expiry time.
Web page requests arriving from users are "anonymous" and basically unrelated to each other even if they are coming from the same user. This is because the HTTP protocol is "stateless" and server can't map requests to specific clients based on just the IP addresses it sees. Therefore, cookies are a crucial mechanism for preserving state information in programs with web-based interfaces. By reading the session ID value (stored in a cookie on client's computer), the server can now recognize associate users with their ongoing, active sessions.
![]() | Interchange and its non-dependence on client cookies |
|---|---|
Many web-based solutions require that the clients accept storage and retrieval of cookies. When cookies are not enabled on client side, the usage of the site is limited, or clients are even denied access completely.
Interchange, on the other side, does not require client support for cookies.
If the storage of cookies is denied or unsupported by the client,
Interchange appends session
information in generated URLs and uses them to continue keeping track of
user sessions. (An example session ID "embedded" in an URL looks like
Session IDs embedded in URLs should theoretically be equivalent to cookies,
and they almost are. The drawback is namely the fact
that once you visit a non-Interchange page, you lose the |
When a new client accesses its first page from the Interchange catalog, Interchange sends it both the requested page and a cookie. At that point, Interchange can't know whether the client accepted the cookie or not — it has to wait for the client to initiate the second page request. (Historically, many application servers always bounced the first request to provoke the second access from the client and to check for cookie support. Interchange does not do it.)
If the user sends a cookie back to Interchange (which, as you see, can happen no sooner than on second request), Interchange knows the client is cookie-capable and there's no need to embed session ID in URLs.
One possibly confusing thing is that, by default, Interchange always appends
session ID information to the URLs it generates — even if clients
have no cookie-handing problems.
If the scratch variable mv_no_session_id is set in the user's
session, the session ID will not be appended to the URL. Furthermore,
on a somewhat related note, if the scratch
value mv_no_count is set, then the page count
(mv_pc=) will not be
appended either. "PC" is a page counter that serves to prevent client browsers
from caching pages.
random
> In any case, you can create the encrypted pwds with: > > 1) makepasswd --crypt > makepasswd --crypt-md5 > > 2) or help yourself with htpasswd/htpasswd2 and htdigest/htdigest2 > that come with apache (htpasswd for crypt(), htdigest for MD5): > > htpasswd2 -c /tmp/temp test > htdigest2 -c /tmp/temp test test It's done with simple Unix crypt by default. To have Apache's htpasswd output to stdout instead of a file, you can do: htpasswd -n test Jon
Data Source Name or a DSN is an application's data source identifier. It provides all parameters for the connection to a database.
In its simplest form, it has the format of
protocol:
subprotocol:
host:
port:
database
It's also possible to explicitly name the parameters, like this:
protocol:
subprotocol:
database=DBNAME;port=PORT
In general, databases contain information, usually in tabular format, where columns define the names and types of contained data, and rows represent entries — database records.
Interchange is primarily using databases to just retrieve values from specific tables, and does not use any higher-level functions of RDBM databases (such as views, triggers, or stored procedures in PostgreSQL). Such things can, however, be implemented in the database independently of Interchange, as Interchange will properly pass any warning or error messages back and forth.
We should say right away that Interchange is completely database-independent. The choice of actual database types that can work with Interchange is large, and Interchange can use some database-like methods automatically when you're not explicitly interested in paying attention to databases working behind the scenes.
Common features are transparently available everywhere (with absolutely no code hacks or special cases required), regardless of the underlying database type used. In addition, almost no field names are hard-coded, allowing for unlimited flexibility.
Keep in mind that the terms database and
database table actually mean the same thing in Interchange
parlance - a database table.
Interchange works with GNU DBM, DB_File, SQL, LDAP and in-memory types of databases.
Regardless of type or other characteristics, each database must be registered
on a catalog level before it's ready to be used, and this is achieved
using the Database configuration directive. It's useful to remember
at this point that multiple catalogs can share the same database.
Three parameters need to be present in a basic Database definition:
an arbitrary database name, text source file with initial content, and the
type of the database.
Text source files are not databases themselves, of course (for performance and other reasons); they are only used to provide initial data for the corresponding database tables.
By default, all database source files are kept in the
products/ subdirectory of your
CATROOT. The ProductDir directive controls the exact location.
The ASCII files can contain carriage return
(^M) characters even in data fields, but must have a
newline character (^N) at the end of line to properly
separate records.
Mac users uploading files must use ascii mode, not binary mode.
Interchange's default ASCII delimiter is TAB. Keep in mind that the items must be separated by a single delimiter (that is, by a single TAB only). Due to the nature of TABs, TAB-delimited files look messy and unaligned when viewed in a text editor. Do not try to fix these; better use the te utility that comes as part of the Interchange distribution to edit such files more conveniently.
Interchange can manage an unlimited number of arbitrary database tables and database table types. Several flexible delimiter schemes are available "out of the box":TAB-delimited file (Type 1, the default): Fields are separated by TAB characters. No whitespace is allowable at the beginning of the line.
code description price image SH543 Men's fine cotton shirt 14.95 shirts.jpg
(You might notice that the fields names and values above are not properly aligned. This is an unfortunate nature of tab delimited files.)
Using the default TAB delimiter is recommended if you plan on searching the ASCII source file of the database.
LINE (Type 2):
Fields are specified each on its own line, separated by the newline
(\n) character. One blank line separates a record
from another record.
code description price image SH543 Men's fine cotton shirt 14.95 shirts.jpg
%% (Type 3):
Fields are separated by the literal combination of
"\n%%\n", while the records are separated
by "\n%%%\n". Users fond of the Unix "fortune"
program may find this format familiar.
code %% description %% price %% image %%% SH543 %% Men's fine cotton shirt %% 14.95 %% shirts.jpg
CSV-delimited file (Type 4): Fields are enclosed in quotes and separated by commas. Again, no whitespace should be at the beginning of the line.
"code","description","price","image" "SH543","Men's fine cotton shirt","14.95","shirts.jpg"
CSV-delimiter schemes might cause problems with ASCII text searching routines.
PIPE-delimited file (Type 5):
Fields are separated by the pipe ("|") characters which
resemble vertical lines. No whitespace is allowable at the beginning of the
line.
code|description|price|image SH543|Men's fine cotton shirt|14.95|shirts.jpg
PIPE-delimited files perform fairly well with ASCII text searching routines.
TAB-delimited file (Type 6):
<reserved> (Type 7):
SQL (Type 8):
LDAP (Type 9):
![]() | Note |
|---|---|
Field names are usually case-sensitive (in fact, that depends on the underlying database type). Always be consistent when naming or referencing fields and you'll avoid the trouble. All lower or all upper case names are recommended. |
If a database is specified to be one of the first six types, then the database will automatically be converted to a more efficient internal structure. Those include DB_FILE, GDBM, or MEMORY. The order of preference and the selection is:
As hinted above, you do not need to use an external SQL database. If you only have a small data set, you could use Interchange's internal databases. This is a tremendous gain for small and quick setups, or ad-hoc Interchange evaluation. However, some functions (order management, for example) will be slower and not as robust without an SQL database. SQL is strongly recommended for at least the state, country, orderline, transactions and userdb tables. Any other tables that will have programmed updates, such as inventory, are also best placed in SQL.
![]() | Database performance |
|---|---|
Do not, however, try to optimize too soon and for no measurable difference. Do not fall in the jaws of premature optimization, your worst enemy. |
Generally, you should make an additional effort of configuring and using SQL databases to achieve Interchange's full potential. Using SQL also makes your data sets easily available for integration with other applications.
In any case, database import and conversion routines are already available in Interchange and you can use them at any point.
Speaking of the source files' behavior, if a file named
is present
in the same directory as
table.sql, then database
table will never be imported from the ASCII text source file.
If there is no table.txt,
the DBI/SQL import will happen once, at
Interchange startup or catalog reconfiguration time (and the
table.sql file will be
created);
Interchange will connect to the SQL database using the specified DSN
(DSN is a standard DBI parameter meaning "Database Source Name").
The table will be dropped (if it already exists in the database) using a
line similar to
table.sqlDROP TABLE .
This will occur without warning, but tableNoImport can be used to
prevent it or otherwise change the default behavior.
The table will then be created again and populated with text source
file data.
If there are any
COLUMN_DEF specifications present in interchange.cfg, catalog.cfg or
products/,
they will be used to create SQL table specification
(which is recommended for clean and correct database
layout). If there aren't any, however, then the key (first field in the text
file, by default) will be created with the type table.sqlchar(16),
and all other fields will be created as char(128). This is
very unfortunate, but the best Interchange can do without your help.
Table creation statements will be written to the error.log
along with, of course, any errors. From our experience, the most common
mistake at this point is choosing column names that sound perfectly reasonable,
but also happen to be reserved keywords in MySQL. (The error messages
appear to be misleading here, so you better take a look at the
list
of reserved MySQL keywords before losing patience with the problem).
Once the database (database table actually, remember?)
is created, the text source file will be imported into it.
For this step to succeed, data typing must be user-configured. In other words,
if say, word "none" is placed in a field while the field
in question
is defined to be of numeric type, database import will not succeed;
consequently, the problematic catalog won't configure successfully
(it will be skipped) and it won't be available when Interchange starts up.
For a complete discussion, please see the Database configuration
directive.
By file-based databases we primarily assume GNU DBM and DB_File. We also call those database types "internal", since in the absence of say, an SQL definition, all inferior formats (such as text source files) are automatically converted to some kind of a file-based database.
Those database types usually work in a way that, on every client access, the appropriate database text source file is checked for being newer than the actual DB file itself. When it happens that it is, the database table is re-imported from the text source file on the fly, and the routine then proceeds as usual.
![]() | Database updates |
|---|---|
It is important to note that, when using Interchange internal database methods, all changes in the text source files cause the databases to be re-created. This can have unwanted effects if the database was modified from within Interchange and the contents have not been written back to the text source files. Another common problem are larger data sets that take noticeable time to get imported to (or exported from) the internal database.
The exact behavior can be controlled via the |
To check if you have GNU DBM and GDBM Perl support available, run
perl -le'require GDBM_File and print "I have GDBM."'.
To check if you have Berkeley DBM and DBM Perl support available, run
perl -le'require DB_File and print "I have Berkeley DB."'.
Sometimes you want to use Berkeley DBM even if GNU DBM is installed and would
naturally take precedence; in such cases, set the
MINIVEND_DBFILE environment variable to a true value
(setenv MINIVEND_DBFILE 1 in csh,
MINIVEND_DBFILE=1 ; export MINIVEND_DBFILE in
sh,
b(a)sh or
ksh).
It is also possible to use Berkeley DBM for just specific databases.
For a complete discussion, please see the Database configuration
directive.
Memory Interchange databases use Perl hashes to store the data directly in memory. Every time the Interchange server is restarted, it will re-import all in-memory databases for every catalog.
Memory databases are used by default only if no database type is explicitly specified, and there is no DB_File or GNU DBM found on the system. Otherwise they can be used for small but high-traffic tables. Keep in mind, however, that since their contents are not saved back to the text files, you'll want to either take care of the data export yourself, or keep the tables stuffed with read-only data.
if you want to force memory databases despite of GDBM_File or DB_File
being present, set the MINIVEND_NODBM environment variable
to a true value (look previous chapter for hints on setting it).
It is also possible to use memory type for just specific databases.
Memory databases import will be performed once at every Interchange startup or catalog reconfiguration time.
For a complete discussion, please see the Database configuration
directive.
We are trying not to impose any database structure that would require our own tools to maintain the data. We always want to keep it such that Interchange data can be maintained via a spreadsheet processor or foreign database tools.
This section describes naming and file usage conventions used with Interchange. This is very important for both understanding Interchange and developing your own custom solutions which build upon officially recommended practices.
Term definitions:
key or code
The words reference the database key. In Interchange, the key is usually the product code or SKU, which is the product part number. Otherwise, key values may be used to generate relationships to other database tables.
It is recommended that the key be the first column of the database text source file, since Interchange's import, export, and search facilities rely on this practice.
field or column
The vertical row of a database. One of the columns is always the key and it is usually the first one, as explained above.
table or database
A table in the database. Because Interchange has evolved from a single-table database to an access method for an unlimited number of tables (and databases, for that matter), a table will occasionally be referred to as a database. The only time the term database refers to something different is when describing the concept as it relates to SQL, where a database contains a series of tables. While Interchange cannot create SQL databases, it can drop and create tables within databases if given the proper permissions.
Interchange uses one mandatory database, which is referred to as the
products database. In the supplied demo catalog
(and in the most of real-world solutions as well), the primary
database is directly called products
and the ASCII source is kept in the products/products.txt
file.
This is also the default file for searching contents with
the search engine, such as Glimpse, HTDig or Swish.
![]() | Note |
|---|---|
Interchange also has two optional databases that are specified in special, fixed formats:
The two above tables cannot be stored in any user-specified format. |
No debugging options are enabled by default in Interchange. See DebugFile for
a quick introduction to enabling debug messages.
Before DebugHost can be used to restrict diagnostics to specfic
set of hosts, the debug mode itself has to be enabled using DebugFile.
Dereferencing is strictly a computer-programming issue, but we will try to explain it in very brief and comprehensible terms, so that you understand the idea of dereferencing and its practical effect when data structures are copied.
Let's say we want to compose a list of a few automobiles. Each entry in the list will contain the fields model, year and mileage.
Theoretically speaking, to solve this real-world problem with the help of a computer, we would create a template (containing the three fields), and produce one instance of the template for each car we add to our list. (How this list is created, how the elements are added and how they relate to each other is irrelevant here).
One imaginary list with three instances could be visually represented in the following way:
Model Year Mileage
list[0] { 'Fiat', 1996, 177940 }
list[1] { 'Citroen', 2001, 66000 }
list[2] { 'Citroen', 2002, 23000 }
There is only one copy of this list in computer memory, and we read or modify the elements by obtaining references (or, pointers) to appropriate entries.
If we take list above to contain the list of references
to the entries, we can
use list[0].Model to retrieve the value "Fiat", or
list[2].Year to retrieve "2002". For both of those fields,
a reference was first dereferenced (or,
followed) to reach the actual data fields.
When list elements need to be copied to another location (usually as part of some bigger plan which, again, we are not interested in), they can be copied by value (with dereferencing) or by reference (obviously, without dereferencing). With copy by value, you would end up with 2 references and 2 different lists (initially they would be the same but afterwards you could modify each with no connection to the other). In case of copy by reference, you would again have 2 references, but both pointing to the same list. Modifying data through any of the two references would have impact on both.
So, when a data structure (or its element) is said to be copied without dereferencing, then in case it was a reference, it is still copied in itself, but all copies point to the same location. In other words, the data is not duplicated, only the access points are.
Product discounts in Interchange can be set at any time. The discounts apply only to the customer receiving them, so you can set discounts based on membership in a club or other arbitrary means.
Discounts are defined using the discount tag,
and are of the following types:
Discount on a specific item - a discount for one particular item.
Key to use with the discount tag is the product's SKU
Discount on all items - a discount applying to all items.
Key to use with the discount tag is ALL_ITEMS
Discount on a particular item at particular time -
a discount for an individual line item, applied if the mv_discount
attribute is set (usually with embedded Perl)
Order discount - a discount applied not to individual products, but to the
total order amount.
Key to use with the discount tag is ENTIRE_ORDER
Discounts within the discount tag are specified using a formula.
The formula is scanned for
the $q and $s variables which are
substituted for the item quantity and subtotal respectively.
The variable $s is saved between
iterations, so that the discounts can be cumulative.
In case of individual item discounts, the formula must be constructed to
handle all instances of a particular SKU found in the user's basket.
There are many ways how same SKU might occur
multiple times in the user's basket (for example, with SeparateItems
enabled) — the same formula will be invoked on every occurrence and
it should always give out the correct individual subtotal.
In case of an entire order discount, the formula is usually simpler and defines a flat discount amount or percentage.
Discounts are applied to the effective price of the product, that is — the price obtained after applying price adjustments.
For examples, see the discount reference page.
In April 2005, Interchange added support for "discount spaces" (using CGI
variable mv_discount_space),
in a manner akin to values space (mv_values_space) or
named shopping cart (mv_cartname). See DiscountSpacesOn
and DiscountSpaceVar for usage examples.
This entry describes how Interchange processes a request after assiging it to a catalog.
Running macro(s) defined by Preload directive.
Checking authorization.
Session, cookie and robot handling.
Redirect GET requests with affiliate code when BounceReferrals
directive is enabled. Effectively terminates processing of the request.
...
Unix Epoch resource at Wikipedia.
User sessions in Interchange are usually kept as files in the
session/ directory (or inside
a DBM database) for each catalog. Since session
data is not deleted after sessions end (or timeout), periodic expiring
needs to be set up to keep the session database or session files from growing
too large, wasting disk space and slowing down directory lookups.
There's no worry that expiring will do any harm, because all our scripts only clean up unused sessions. Active users will not notice any change.
The simplest way to expire catalog's session files is to run
expire -c CATALOG_NAME.
For convenience, there is also expireall script which
reads all catalog entries in interchange.cfg and runs expire on them.
The expire script accepts a -r option
which, when DBM sessions are used, tells the script to reorganize database
files and recover lost disk space.
On a UNIX server, it's most useful to run expireall
from crontab. As the Interchange user, run
crontab -e to edit crontab data, and enter something like:
# once a day at 4:40 am 40 4 * * * /PATH/TO/perl /PATH/TO/INTERCHANGE/bin/expireall -r
![]() | Note |
|---|---|
If a session saved search paging files in |
When file-based sessions are used (no DBM), then you can use a custom script like this:
#!perl
# expire_sessions.pl -- delete files 2 days old or older
# invoke as: /PATH/TO/perl expire_sessions.pl /PATH/TO/CATALOG/session/ ...
my @files;
my $dir;
foreach $dir (@ARGV) {
# just push files on the list
if (-f $dir) { push @files, $_; next; }
next unless -d $dir;
# get all the file names in the directory
opendir DIR, $dir or die "opendir $dir: $!\n";
push @files, ( map { "$dir/$_" } grep(! /^\.\.?$/, readdir DIR));
}
for (@files) {
unless (-f $_) {
warn "skipping $_, not a file.\n";
next;
}
next unless -M $_ >= 2;
unlink $_ or die "unlink $_: $!\n";
}
This script can be adjusted as necessary. Refinements might include reading the file to "eval" the session reference and expire only customers who are not registered members.
If your files get chown-ed to root every day, then you probably used root's instead of Interchange user's crontab file. Either move the crontab to the Interchange user, or use su to swith users from the root account:
44 4 * * * su -c "/PATH/TO/INTERCHANGE/bin/expireall -r" IC_USERNAME
The above does not, however, clean temporary files from the ScratchDir
directory. We don't often use the expire scripts any more. We just use
a small standalone script clean_session_tmp:
#!/bin/sh
for DIR in $*; do
for i in session tmp; do
if test -d "$DIR/$i"; then
find $DIR/$i -type f -mmin +480 | xargs --no-run-if-empty rm
find $DIR/$i -depth -type d -empty -mtime +2 | xargs --no-run-if-empty rmdir
else
echo "$0: $DIR/$i doesn't exist.";
fi
done
done
using a cron entry similar to:
44 0,4,8,12,16,20 * * *DIR/bin/clean_session_tmp/path/to/catdir1/path/to/catdir2
The set of configuration directives prefixed "External" allows export of Interchange variables for use by other programs and languages, such as PHP, Ruby or Python.
The three directives are External, ExternalFile and
ExternalExport.
The current functionality is just a proof of concept and is not for serious use. The interface needs serious work.
A working example for accessing data from PHP is provided in the
External reference page.
In general programming terms, a false value is one
that is either 0 (zero) or ""
(an empty string).
Since the Perl programming language has a notion of undefined values, they too are considered false.
With Interchange 5.3.0, Interchange supports so-called "features". The whole purpose of the new "Feature" facility is to allow easy installation of new capabilities to Interchange.
Interchange already has the convention of "extensions" which allow you to put together features to add to Interchange. But the installation is manual, and requires good docs to make it easily installable for end-users. Also, many features require access to the global configuration. There's also another problem at sight, namely that of feature creep, since everything was just being added to the "standard" catalog.
The basic mechanism is simple:
Inside "feature" modules, there are three special kinds of files, called by
extensions .global, .init and
.uninstall.
(In the included quickpoll feature, these are named
quickpoll.global and quickpoll.init).
If a file has the extension .global, it is added to the global
configuration. The included quickpoll feature, for example,
adds the quickpoll ActionMap, and two usertags:
poll-answer and ascii-graph.
If a file has the extension .init, it is run once —
the first time
the target catalog is accessed. Again, in the quickpoll example, it is used to add
mv_metadata entries and a couple of sample polls.
All other files in the directory are catalog configuration
(quickpoll.catalog.cfg for a concrete example).
It could have also been
broken up into say, files quickpoll.sql and
quickpoll_answer.sql.
All subdirectories contain files which are copied to the
catalog directory with the same relative path. In this
case,
ICROOT/features/quickpoll/templates/components/quickpoll
would go to
CATROOT/templates/components/quickpoll.
The .init file, when run, sends its output to
(and that would be ConfDir/init/FEATURE/FEATURE.initetc/init/quickpoll/quickpoll.init for
the concrete example.)
Once it is run, the existence of the file prevents it being run again.
Uninstall files, those with the .uninstall extension,
are ITL files that can perform any uninstall
functions, and they run with temporary AllowGlobal access to
allow dropping of tables, unlinking of files, etc.
Automated uninstall features include removing any files installed
as a part of the feature -- providing they have not changed. If
the file was edited and is not identical to the originally installed
file, then it is left there and a warning issued.
Uninstall creates file
to note the uninstall, and which prevents the Init process from happening
again (assuming Interchange has not been restarted since the
feature installation).
ConfDir/init/FEATURE/uninstall
The uninstall routine is called with the uninstall_feature tag.
![]() | Caution |
|---|---|
The catalog user must remove the
Also, there is a short window where a SQL table, if dropped
as a part of the uninstall procedure, could be re-instantiated
based on the existence of the configuration in memory. It
is recommended that if |
Interchange filters are usually small routines that perform various (arbitrary) transformations of user input.
There are filters that trim the text to a specified maximum length,
substitute characters in strings, make user input display- or storage-safe,
or even serve as value equivalents.
Using existing filters and creating new ones is very simple.
Interchange "form actions" are basically Perl subroutine definitions that you can
execute upon form submission. Which form action to trigger is specified by the
mv_action form variable.
Successfully executed form action should return a true value, upon
which Interchange would display the page specified in mv_nextpage.
If the form action returns false, Interchange will not display any page.
Using FormAction, you can both define new and override existing
form actions.
"GET" resource at Yukka Korpela's website and faqs.org.
In Interchange parlance, "gating" is the process of controlling access to certain pages. See Control Access to Certain Pages HOW-TO HOW-TO entry for further information and examples.
The first step is to fulfil the prerequisites of the payment module
(listed in the individual module documentation below) and enable the module
in the global configuration file with the Require directive:
require Vend::Payment::NetBilling
If we are using only one gateway in a catalog, setting up
MV_PAYMENT variables is sufficient.
| Variable | Purpose | Notes |
|---|---|---|
MV_PAYMENT_MODE | gateway mode name | |
MV_PAYMENT_HOST | gateway host name | optional (predefined in module) |
MV_PAYMENT_ID | merchant identifier | |
MV_PAYMENT_SECRET | secret part of credentials | password or certificate |
MV_PAYMENT_REFERER | referring URL | |
MV_PAYMENT_TEST | test mode |
An example configuration looks like:
Variable MV_PAYMENT_MODE signio Variable MV_PAYMENT_PARTNER verisign Variable MV_PAYMENT_ID nevairbe Variable MV_PAYMENT_SECRET foobar
With the Route directive it is possible to specify payment gateways
for special purposes. The payment route should set all relevant payment
parameters for the gateway, otherwise the settings from the MV_PAYMENT_* may
leak into the route.
Route signio partner verisign Route signio id nevairbe Route signio secret foobar
The following payment gateway transactions are known by Interchange:
| Transaction | Description |
|---|---|
| avs | Address verification (AVS) |
| auth | Payment authorization (Charge) |
| return | Credit |
| reverse | Reverse former transaction |
| sale | Charge and capture |
| settle | Capture of an authorized charge |
| void | Cancel or refund payment |
| abort | Abort pending capture. |
Modules for the following payment gateways are included in the Interchange source code:
| Module | Name | Mode | Description |
|---|---|---|---|
AuthorizeNet | AuthorizeNet | authorizenet | |
BoA | Bank of America | boa | |
BusinessOnlinePayment | Business::OnlinePayment | onlinepayment | wrapper for Business::OnlinePayment |
Cybercash | Cybercash | cybercash | |
ECHO | Electronic Clearing House, Inc. | echo | |
EFSNet | Concord EFSNet | echo | |
Ezic | EziC | ezic | |
Getitcard | Getitcard | getitcard | Prepaid cards from Getitcard. |
ICS | Cybersource ICS | ICS | |
iTransact | iTransact | itransact | |
Linkpoint | LinkPoint | linkpoint | |
MCVE | Mainstreet Credit Verification Engine | mcve | |
NetBilling | NetBilling | netbilling | |
PRI | Payment Resources International | PRI | |
PSiGate | PSiGate | psigate | |
Sage | Sage Payment | sage | |
Signio | Payflow Pro | signio | |
Skipjack | Skipjack | skipjack | |
TCLink | TrustCommerce | trustcommerce | |
TestPayment | Payment Test | testpayment |
The AuthorizeNet module implements the ADC Direct Response method for AuthorizeNet version 3.
OpenECHO module from http://www.openecho.com/.
The Getitcard payment module is used for purchases with prepaid cards issued by GetitcardŽ (http://www.getitcard.com/).
Required parameters are id and keyfile.
The domain name of the LinkPoint Secure Payment Gateway (LSPG). Default is
secure.linkpt.net for production and
staging.linkpt.net for testing.
File name of the merchant security certificate. This file should contain the RSA private key and the certificate, otherwise you get an error like "Unable to open/parse client certificate file."
The Netbilling module implements the Netbilling Direct Mode 2.1.
This is your account and sitetag separated by a colon (ACCOUNT:SITETAG). ACCOUNT is the number of your Netbilling merchant or agent account, as a 12-character string. Required for ALL transactions. SITETAG is the site tag of your website configured in the Netbilling system. Required for membership transactions, optional for others.
Net::TCLink module from http://www.trustcommerce.com/tclink.html or CPAN.
Hello, World! resource at Wikipedia.
Interchange functions are accessed via the Interchange Tag Language (ITL). The pages in a catalog may be mostly HTML, but they will use ITL tags to provide dynamic content and access Interchange functions in general. ITL is a superset of MML, or Minivend Markup Language.
ITL tags perform all kinds of operations.
There's more than 200 standard predefined tags, and the
UserTag facility allows you to create your own custom tags,
indistinguishable from the ones "built-in". To get started
with custom tags, see usertag glossary entry.
ITL tags are similar to HTML, in that they accept attributes and that there are both standalone (non-container) and container tags.
A standalone tag has no ending element, such as value:
[value name]
The above example will insert user's name.
A container tag has both beginning and ending elements, such as tag if:
[if value name] You have provided us with your name. It is [value name]. [/if]
In the above example, you see that container tags are in general useful only when content is provided in their body (the place between the opening and corresponding ending tag).
There must be no whitespace
between the left bracket ([) and the tag name; [forum] is
valid, [ forum] is not!
We've covered the most basic syntax above. If you need to pass attributes to the tag, you do that in the opening section. If the tag is a container, then body text can additionally be specified between the opening and closing marker:
[tagnameparameters_or_attributes]Body Text[/tagname]
Note that some Interchange macros (drop-in text replacements)
may look like tags or end tags. For example, [/page] used to
be a macro that expanded to </a>, but page
itself was not a container tag