Products | Scripts | Services | Tutorials | Books | Links | Contact | Bulletin Board

The CITY Shop

Overview | Concept | Licensing | Demo/Download | Installation | Gallery | Last Updates | FAQ

Templates | Views | Engines | Libraries | Main Setup | Shop Setup | Database | Session | Shipping

Shop Setup

Most of the "ways" of your shop are defined in the All the basic settings, runtime options, database settings, and data queries are controlled here.

Performance questions

We agree that the file is big, and it's not getting any smaller as the shop evolves, but we chose to sacrifice speed for the advantage of simplicity. If you run ModPerl, that should not be an issue anymore, since the file is compiled only once, with the first click. On average machines, the standard click takes anywhere between 1 and 2 seconds, whereas on a ModPerl implementation, you can achieve about 5 clicks a second. The size of your database and the nature of the click might add some slack, but that is not anymore the issue of the setup file.

Basic working model

Once the module is loaded, the main script can and will invoke the object constructor, with the line:

my $S = new ShopSetup($T);

This will assign to the variable $S an hash containing all the system setup values. The library has some global variables, that get referenced in this hash.

Global variables

When you run ModPerl, it is good to keep as many variables as possible as global, if their value does not change in time. These are script messages, CSS styles, and other initialising values for shop modules. You can even make global the database definitions, if you feel like it. The reason I keep them lexical is that it makes debugging easier, you don't need to restart Apache everytime you change a thing in the setup file.

One funny thing that can happen to you, is when you change the data in a global variable, and suddenly nothing works anymore. This is a quite nasty bug to fix, since it does not happen at the first click, but rather when the offended code is being accessed next time. Check and test your customized code thoroughly.


This variable is here only for the fancy, since the shop does not check versions right now.


This is the address that appears on the printable orders. You can redefine the system key -SHOP_ADDRESS if you need to display a different address depending on some logic that you might implement in your shop. An example to that, is when you have corporate customers and normal customers, which, after logging in, get to see a different view of the shop and the ordering process.


This is the style applied throughout the shop, that is, if you use the standard templates. You can include static embedded styles, if you want. Linked files will not work, since this is a script, not a html document, coming from the web root. Some browsers do not like it, when you try to give a path to a CSS file. It is also possible to extend the shop.cgi to use a different CSS value, depending on what action was taken. We chose to keep it simple. The variable is saved in the system key named -LAYOUT_BASE_HTML_STYLE, and is used in the main script only.


This variable holds an anonymous hash of links to partner sites, or plain advertising links. We only put there the "default", which will be displayed on the main page, but you can add your own as you wish. The correspondent system key, -SHOP_ADVERTISING, is currently being used only in the , but you can define values and use them throughout the shop as you wish. We recommend keeping it at the VIEW level.


Some form fields values need to be within a certain range, or of a certain type. This anonymous hash, saved in the -CHECK_FORM_VARS system key, holds the field names and the field types for the input data that needs to be checked. These are the generic fields of the shop navigation, but you can experiment with type-checking other form values as well. The CheckInputData() routine in the main script takes care of validating the input using these defining values.


When performing a search in the database, you want to exclude some words that will be too obvious and do not improve search result quality. For example, words like: "and", "not", "a", and others will be ignored from the list of the keywords entered in the form search field. Every language has its own list of such words, therefore we implemented it as a hash, with a list of words for every language.

The system key -SEARCH_EXCLUDED_KEYWORDS holds only the list corresponding to the current language. This list is currently used in the


This anonymous hash holds the basic settings for the payment gateway. Saved in the -MERCHANT_DATA system key, this hash is used in the It is needed if you use online credit card or check processing.


This anonymous hash holds the information for defining the currencies used in the shop. The keys explained:

-BASE_CURRENCY is the currency code for the currency considered to be the base for calculating all the prices. Once you set this up, you should not change it, unless you change all the prices in the product data table.

-DEFAULT_CURRENCY is what the shop displays by default, if the form parameter "curr" is not set. This means, you can change what currency you display, as you do with the language. Due to the sensitivity of the parameter, we do not comment much here about this feature.

-SECONDARY_CURRENCY If the shop is to display a secondary currency, this is what you set here.

-CURRENCY_FIELDS this is an array of field names corresponding with the next parameter

-DATA contains a hash of currencies and their description. It is important that you define ALWAYS the -EXCHANGE_RATE of 1 for the base currency, otherwise the shop with end up miscalculating orders.

Since this key needs a bit more explaining, here is a description of the fields:

  • -CURRENCY_SYMBOL is the same as the key name
  • -CURRENCY_SYMBOL_NUMERIC is its numeric ISO equivalent. Please use the following link to get more information about the correct codes:
  • -TEXT_SYMBOL is the symbol used by the text display mode, used in the emails sent to the user and the shop manager
  • -HTML_SYMBOL is the HTML equivalent symbol for this currency
  • -NUMBER_FORMAT is a sprintf string that is used to format the currency.
  • -EXCHANGE_RATE is the multiplier used to convert the currency in report with the -BASE_CURRENCY
  • -SYMBOL_POSITION is a binary flag; when set, the currency symbol is placed in front of the number, otherwise it is placed behind the number
  • -SYMBOL_USE_SPACE is also a flag, that enables inserting a space between the currency symbol and the number
  • -SYMBOL_COMMIFY contains the character used for the 1000 separator. If you use here a dot, the shop will use a comma for the decimal separator. The Comma is the alternative default, but it needs to be specified.




The object construction

As said before, it all lies in a hash. It is simple and convenient. You can add keys to it as need arises, modify database and query data as you feel fit, and look good doing it. It might be not so easy on the memory usage, but it certainly makes development easy. Even on NT, consider that your site will have a constant load of 3 hits a second, every click takes 3 seconds or more, you will not use more than, say, 60 MB RAM, considering the absurd thought that you want to do that not using ModPerl, that is. This is being calculated considering that a process eats 5MB just because it's Microsoft; add to it your 1 MB of database read data, and variable space. Unless you are running a web server on a hardware built in the middle-ages, memory is not what hurts you, processor power is.


Setting up the shop language

Setting up the shop working language is important before defining any database queries, paths to libraries, or anything else that is language-dependent. The variable $LanguageField contains the corespondent value defined in the %LangMap. The form field for the language preference is "L".

As of the beta 2, the ShopSetup uses a mapper hash from the shop display language to the appropriate database field name extension that is used for the language:

my %LangMap = (
  'eng' => 'ENG',
  'ger' => 'GER',
  'fre' => 'ENG',
  'hun' => 'ENG',
  'ita' => 'ENG',
  'dut' => 'ENG',

That makes a building a flexible multi-language database very simple. Keep in mind that every database module in the manager has to have appropriate fields defined. For more information, look in each module's header. If you don't know Perl, maybe that is a thing that you should not mess with :)


Setting up the shop currency

Setting up the shop working currency is an optional step, that you can perform, to improve the integration level of shops selling in countries with dual/multiple currency. The shop will handle all using the base currency, but the customer will see the alternate currency. If all you want is to display the alternate currency, enable the key "-SHOP_CURRENCY_SECONDARY", and make sure you have the proper entry in the global hash $Currency. This hash also contains the exchange rates, calculated from the base ("-BASE_CURRENCY").

Describing the data tables

The database tables can come from different sources. For the time being, the shop uses a flat-file database, which is very convenient for small shops with up to 3000 items. Above that, if you want performance, you can implement SQL.

Every data file (table) has a hash assigned to it, that uses the following keys:

  • -TYPE - this has only one valid value now, "File"
  • -FILE_PATH - for the type "File", this is the path to the actual file
  • -FIELD_NAME - this contains a reference to the array of fields in the data record
  • -FIELD_KEY - points to the field that is the key of the table
  • -FIELD_TYPE - is a simple hash of correspondence between the fields and their type. An autoincrement key field needs to appear in here, with the value "auto". Multiple value fields, defined by the value "multiple", are usually separated by "::".

More about the definition of a data file can be found in the documentation of the module.

All the data tables are referenced in the system key -DB.



To make some parts of the code easier to understand and have more control over some processes in the shop, we define "Data Sources" in the setup file. They are referred to by the system key -DATA_SOURCE.

A data source is nothing else but a pre-defined database query, for the most obvious queries made in the shop. You can get more information about the required keys in a query, in the documentation of the module.



Yeah, I know, the name is not appropriate. We put together all the information needed to create a select form field, or a menu, from the data source to the form field definition. This data will be processed in the, through the method CreateFormField(). More about the structure of the hash you will find in the documentation of the package. You can access the queries under the system key -DATA_QUERY.


$DatabaseMapToForm - Mapping table field names to form field names

It is a good practice to never directly refer your database table field names in the form fields. Whatever you get to change then in your code, or in your database definition, this hash of field names will help match to the right one. You can access the mappers through the system key -DB_MAP_TO_FORM, which is a reference to a hash of hashes, one for each data table.

$DatabaseMapToSession - Mapping table field names to session field names

As the one before, this hash maps field names to their session file counterparts. This is useful for the case when you want to save a datarecord to the session file.

For the both paragraphs above, we simplified the definition method of the assignments, defining a meta-mapper as follows:

-MAP_DB_KEY is a flag that enables the mapping of the table key field to a form field.

-MAP_CUSTOM describes the explicit field mappings, if the database field name is not the same with the form field name. All fields that are not defined here, will be mapped 1:1 with the database

-MAP_EXCLUDE is an array that lists the database fields that should not be mapped in any case.


The main system hash

After defining all the stuff listed above, we will map it to keys in the system hash. All the routines that are called in the shop pass a reference to this hash, under the variable $S. Some of this data is dynamically assigned, some of it is only read where needed.

We will list the more important keys of this hash (that are not too obvious by their name), what data they store, and where they are used. If you want more information about other keys you see, please ask us.


these are the generic form tags used in the shop. They are defined in the WhatShop() routine in the main script, and are in the format: "<FORM METHOD="post" ACTION="shop.cgi">". If you want some fancier ones, with name, target, and other tag extras, you can build your own custom tags and use them where needed. The -FORM_TAG_ONE_CLICK adds a javascript that prevents the user from double-clicking the submit button.


These are the base links to the shop and manager scripts, with the basic information needed to pass along shop, language, session, and eventually cart information. The format of the link is: "shop.cgi?&shop=city&L=eng&session=141207192&cart=234234".

The key is set in the same routine as the form tags, and completed with all the basic info in the routine WriteHeader(), also in the main script.


these keys store basic information about common locations to all the shops. The first one is not used anywhere yet, but can be prepended to any URL formed from the script, or even be used in re-calculating the image links on the page. The next two hold the script names for the shop and for the manager, like "/cgi-bin/store/store.cgi", with no parameters, and can be used to build links.


The default method for the shop is POST.


Here you define the encryption methods, by name. You can then in the shop use these together with the to encrypt/decrypt different data. We will give here as an example, how you could use it in your code:

  $Data = $Encrypted =  'Data to encrypt';  
  my $EncryptMethod = 'pgp';
my $EncryptSetup = $S->{-SHOP_ENCRYPTION_SETUP} || '';
if ($EncryptSetup && $EncryptSetup->{$EncryptMethod}) {
eval "use CryptLib;";
if (! $@) {
$Encrypted = CryptLib::encrypt($EncryptMethod,
$Data, $EncryptSetup->{$EncryptMethod}); }


These are the emails used for processing the order emailing to user. If missing, the next key will be used.


This is the email that is being used to send the order information to the shop admin. It is also used everywhere an admin email address is needed.


These keys are replicating the mail settings from the If you want to customize the mail parameters for every shop (unlikely), you can enter here the right values (see the file for more details.


Thes keys holds the error log path and file name.


This key holds the path for the shop libraries. It is built based on the shop definition in the


These two keys hold the path (used for image upload in the manager) and the URL to the images.


The value of this key is the directory (preferrably absolute path) to where the downloadable content should be copied, when you upload a data file. That directory will have to be aliased or reside below the web root, if you intend to offer download links after the sale. We will rather recommend to use a push mechanism instead, since that way you can customize the process on a per/user basis.


Every shop has an upload directory, where all the uploaded files land, before being redistributed by the script where they are supposed to go. In the case of images, the manager will move the uploaded images in the appropriate folder, and rename them to match the product ID. The "SHOP_UPLOAD_PATH_DATA" is for the downloadable content.


For all the products that have no image, this is the default image displayed by the shop. it is meant more as a placeholder. We will extend in a future release the categories, to support a custom image, but for right now, there is only one placeholder. The second keys triggers displaying of a standard image as a placeholder for missing images. Since we want to extend the concept of customizing the "missing image" by categories and/or manufacturer, this is a temporary fix.


These are the paths to the main shop directories. Unless you want to share some among shops, you should use the defaults. You can alias the "-SHOP_PRODUCT_HTML_PATH" somewhere under the web root, if you want to offer static content. In that case, the files should have a refresh tag that will load the store with that page.


This is the path for the templates used for admin purposes. For example, the user might have selected a different language, but you want the admin mail to come out in english instead.


If this flag is set on 1, the shop will check the table ipdata.db for IP address matches. If the client address is found in one of the ranges defined in the ipdata.db, the client is seeing the template AccessDenied.html. The table ipdata.db has the format:


and any IP within this range will be denied access.


This path is used by the template processing. If the file is under this path, the image links are re-calculated if they are relative. For example, if you have an image defined as follows:

<img src="products/myimage.jpg">

it will be interpreted by the browser as:

<img src="/cgi-bin/store/products/myimage.jpg">

which of course is an invalid path. The script will calculate the path resulting from the page absolute path, and reformat the tag to display the correct image path.


The first key is a hash of paths used for the static class pages. With that, we mean product pages, category pages, etc... If enabled for a certain class, every time when the shop receives a link with the key as parameter, this path will be check for the existence of a static file. This can be in the same format as a template, but can also be a static page, with a minimal set of custom tags.

This is where the second key comes in the action. If this flag is enabled, and the shop receives the parameter spage , this parameter value is used to retrieve the correspondent static page from the shop web root


This is the path where the shop finds the views.


This is the path for the language-specific folders. These folders are the 3 digit lowercase ISO names for the languages.


This is the path for the user sessions. It has to be writable by the script.


This is the path for the flat-file database. It has to be writable by the script.


This is the path for the user carts. It has to be writable by the script.


This is the full path to the shop error log. The has been extended to support logging of events, with the typical call:

   'ShopOrderLib', '_AddOrderToDatabase', $ErrP);

As expected, the parameters will be saved in a pipe-delimited file.


Set on 1, the first keys enable the saving of every single order in one file. The last keys value are the directories that hold all the orders, as single files. The last one, is where the admin mails are saved, as a backup for when the email daemon fails.


If you want to save the orders in one common file, set on 1 the first keys. The last keys value will be the file name.


Set on 1, this key enables the post-processing of orders. After the order is placed, and before sending the email to the user and admin, we implemented the chance for you to customize some action that will be performed in relationship with the ordered item. The call is in the, and the processing is done in the If you want to use it, you can either add a field to the product table, named "RoutineName", as the code is written to query for that value, or even customize the routine, to support some other mechanism, or even a separate table. We did not implement anything with it yet, but with the first practical example, we will update this file with more details.


Set on 1, this key enables the discount table to be checked and the discounts applied to products.


Set on 1, this key enables upselling of items in the cart. A lot of people will not need upselling, since they have just a few items in the database, but if you are planning on a huge inventory, you will have a use for that.


Set on 1, the first key enables the checking of stock availability in the, and update of the stock data in the The other keys are triggering the way stock is being displayed, and if the total of items backordered should be displayed or not. The last key triggers the hiding of the items that are out of stock and cannot be backordered.


If you disable either of these, the correspondent user information will not be saved on file.


If you disable this key, the order data that contains online delivery items will not be displayed


If enabled, the extended category data will be displayed, when the shop receives the parameter "Category". This is basically happening for the category pages only.


If some items are disabled in the database, they will not be displayed, should this flag be set.


These two keys are flags that determine if the orders are being emailed to the site admin and/or the user.


Normally, you would not want to enable an user when they did not positively receive the order confirmation. The reason for that is, that the user email could be wrong, and they never got the order confirmation in the first place. If you enable this flag, the user will be enabled on the fly, when the order is placed, otherwise only when they click on the validation link that gets sent to them by email.


When enabled, the validation emails sent to the user contain secure links, so the user logs in secure mode by default.


It does what it says, it logs out the user after successfully placing an order.


This is one of the most problematic tags. When enabled, any click on a link or a button that would bring up the order form, comes up in secure mode, if the secure mode is defined. It does not work on all servers, since some servers are configured to rewrite the http headers, thus messing up the redirect process.


We set this on 1 by default. It will not allow an unauthenticated user, to reach the order form. It is better so, but if you want to let them checkout without logging in, disable this flag.


This flag set, only the authenticated users can add items to the cart. Of course, they will not be able to checkout either.


This flag set, the shop will only display prices to authenticated users. The not authenticated users will also be unable to add products to the cart, or checkout.


This is a hash of tables associated with the product table, by the item key. Of course, the table needs to be enabled and valid.


This hash is a mapper between the user group and the promotion applied by default. You can, for example, give a 10% discount on a certain class of items, to the people belonging to a distinct group.


If the flag is enabled, the tax field in the states/countries tables will be considered a multiple field. The second key will contain an array of tax categories, which describes the structure of the multiple field.


This is an array of session records that will be resetted when the user logs in


This is an array of session records that will be resetted when the user logs out


This is an array of session records that will be resetted when the user places the order


This key holds a reference to an anonymous hash, that maps the buttons to standard templates. Some of the actions in the shop set internally these button values, so the right template will be loaded.


As the one before, this is a mapper hash, between the template names and the actual files used for it. That way, we do not handle file names as form field values, anywhere in the shop.


Every template has at least one "view" which loads, executes, and displays the result of a shop "view" library. These are packages located in a language-specific directory, please see the views documentation for more info.


These are the form field names that are used in an account/search process. The first have a place in the ShopUserData.lib and the The second are used in the _FormatSearchLink() routine, in the package, and will be built in the link used to browse through the search results, as well as saved in the session file. See the docs for the for more info. All these fields are the fields that we validate before querying for their value.


As we saw at the beginning of this file, we defined a hash of "non-keywords", which will be accessed through this key.


This key holds an array reference of field names. These are the fields used to build the navigation link through search results.


This key holds an array reference of field names. These fields are used in the authentication process. If you customize your routine, you need to add to this array all the fields you add in your customization process.


These key holds array references of field names. These are the fields used in the order process, that do not belong to specific areas. The second key holds the fields required for the order form.


These are the fields used for the billing and shipping fields of the user data.


These are all possible fields used for the payment screen, and the fields that are required for that step.


Depending on the payment method, there are certain fields, some of them required, that are listed under these keys. If you customize the payment process, add the new/changed fields in these arrays.


These are the template file names that will be used to format the order and the order information that gets emailed to the shop admin or the user.


As described in the header, this key holds the reference to a hash of form field types, that are checked at the beginning of the main script.


This holds the lifetime of the cart, in days.


If a cart was deleted(expired) and the user claims to have it, setting this value on 1 allows the shop to use that cart id, basically creating a new file with the same name.


The first key holds the data in the cart, after the cart was read, the others are just flags to point to the status of the cart/processing.


This key holds an array ref of the cart fields that will be saved in the table "orderdata".


These are display modes used for the product list or the search results


This is a hash of display modes, and their parameters. As the two listed above, there are many other product list display modes, and here is a list of the parameters:

-UPSELL_ITEMS is the number of items upsold in the footer of that view. If not set, or set on 0, no upsell items will be displayed in that display mode

-MAX_PER_PAGE is the number of items that will be displayed on a page. If more items were found, a page navigator will be displayed

-SORT_BY this is the meta-name of the field to sort the results. Valid values are:

  • pid - ProductID
  • cat - CategoryID
  • product - the product short description field (language specific)
  • man - ManufacturerID
  • mpid - ManufacturerPID
  • author - AuthorID
  • price - ProductPrice

These are defined in the following files:


If you want to add more, let us know, we will be happy to do that for you, for the sake of keeping the standard shop consistent



The first one defines how many products per page are displayed in the search result, the second limits the number of hits returned by the database query. These are functioning as defaults, if the specific display mode is not specified in the -SHOP_DISPLAY_MODES hash.


This is a symbolic name for what the shop is sorting the search results by default. For the time being, only the value "name" is valid, which means to sort by the product short description. We avoid to put here any field names, since later on, we will display also links to static html pages, where then the "name" will stand for the file title.


These are the actual database field names, gathered in an array, that will be used to search for the keywords entered by the user.


This array holds all the delivery methods to be displayed in the manager for defining how the product is delivered. It is not really used in the shop, but might be in a later release, this is why we put it here instead of the


These values are used by the shipping routine to properly calculate shipping.


The first key holds an array ref. of all the shipping methods allowed for the shop. Depending on what you customized in the shipping routine, you can add to this array the symbolic names. One name is here interesting, the "free" entry. If you have the second key set on "1", free shipping will be offered as an option. No, we did not implement anything like "free shipping for more than x items". It will be implemented on request. The -SHOP_SHIPPING_METHOD_DEFAULT holds the shipping method that should "stick" if the user does not define one.


If enabled, the shipping will be calculated by the number of items, instead of the weight. Do not enable, unless you know what you do.


When set on 1, this key triggers autofilling the credit card data fields with the data from the billing form fields.


These keys define the available payment modes, the default mode, and the list of all the credit card types accepted by this shop. Whether you use an online merchant account or not, it is useful to define these fields in advance, so you can take the heat off the EPI modules.


These are the fields in %$OX that are to be reformatted as a price before display in the order form or in the email sent to the user. Follow up the code in the and if you want to understand how that works. Yes, you should look at the code, it will not bite you :)


This key IS OBSOLETE! We have already a table named "cities.db" that implements tax and handling fees!


The first two keys hold the hashes defined in the beginning of this file, pertaining to multiple currencies. The last key refers to the entire currency configuration hash. If you want to disable the secondary currency, just comment out the -SHOP_CURRENCY_SECONDARY.


This key will stay on 0 for a while... we do not like cookies, nobody does. We implemented some support for cookies when you use the module, and honestly we discourage their use, given the piss-poor security that they offer. Do you want to do it like a man, track the user's IP address to make sure it's the right one. Most of the cookie-specific stuff is relocated in the session file. It's safe there.


These are the specific records saved in the cookie, prepared so that the will have no work with it.


If you want to offer some associate links, for some products, so that the user will leave your site and take his business elsewhere, we provide the glue for it here. The first key holds the mapper hash for every associate, and the links used for it; the second is the display text for that associate, then the third is used in the manager to display the name of the associate.


Advertising is important. You might want to show some links on the main page, some on the order page, whatever suits your fancy. We described in the beginning of this file how this key works.


We try to accomodate everybody. if your product options are affected by the discount applied, set this on 1. This is a global value.


This key points to the merchant configuration hash, described in the beginning. If you do not use an online merchant, or you don't use it for a certain period of time, you can disable it by commenting it out.


If the first one is set, the shop will assign to the template, if the tag <cityshop:HTMLStyle/> was found, the value of the -LAYOUT_BASE_HTML_STYLE


If this has any valid value, its value will be displayed by the tag <cityshop:JavaScriptHeader/>.


This points to a hash of table names, that point to the actual table descriptions. They are NOT THE SAME AS THE TABLE NAMES!!!. For example, the order table is described as follows:

 'order' => $DBOrders,

and the table is actually named 'orders.db'. The reason we do that, is that we want to be able to rename the tables as we wish, without affecting the shop code. In the shop we can use the 'order' as the descriptor for the order table, all over the script, and we can redefine the real name in the ShopSetup at any time.

PLEASE, PLEASE, read this again and understand the difference!


This holds the hash of mappers between the table field names and the form field names. Please see the description of $DatabaseMapToForm, earlier in this file.


This holds the hash of mappers between the table field names and the session field names. Please see the description of $DatabaseMapToSession, earlier in this file.


This holds the array of database language field suffixes displayed in the manager.


This holds the array of required fields, by the database language field suffixes. It is used in the manager.


This is also used in the manager and needs a bit of explaining. If some of the language fields are missing, and they are not in the list of required fields, their value will be auto-filled with the value of this suffixed field.


This holds the data sources, as described previously in this file.


This holds the data queries, as described previously in this file.


if set, no error message regarding invalid shop tags will be displayed.


This key enables the display of the form variables and the environment settings, at the bottom of each page.


This holds the hash describing the authentication module. See more about that in the description of the authentication process.