Documentation for application_top.php for This description follows the applicaton_top.php code (in the catalog/includes directory). This file is included at the top of every file that drives the output for a page (in the catalog directory). Essentially, it sets up the environment, functions, classes and data structures used to populate information and even html pieces for the page. The best way to use this pseudocode is probably as a reference. As you are reading another php file for , it may reference funtions or classes that you may not recognize. A quick text search within this file might clear up some confusion. If there is an included file, this doc drops into the pseudocode for that file, following the flow of the program logic. It then returns to the file that includes it. Headers show where these branches occur to include files. -----Begin Statements Parsed by application_top.php: Application_top brings in includes/configure.php, which sets webserver and path constants. This file sets constants for the path names for many include files that follow throughout this script execution. Next application_top requires filenames.php from the includes directory. This file defines the filenames used in the project, which are critical for finding and reading these files as we trace the program logic. The constants that are set all begin with "FILENAME_...". Next application_top includes the list of project database tables in "database_tables.php." It assigns the names for the different db table names. It assigns these MySQL table names to constants, which all start with "TABLE_...". Note: Understanding where application parameter constants are set helps tremendously when reading the code. In short, general configuration parameters come from configure.php (see above), constants for database table names come from database_tables.php (see above), store-specific parameters come from the configuration table in the MySQL database (see several paragraphs down), and language linked constant labels come from english.php, german.php or espanol.php under the includes/languages directory. These language files are "required" or brought in near the end of the application_top.php code, as described many pages below. The next line sets the constant BOX_WIDTH to 125 pixels for the default box width on the pages. The next line requires the database.php, where the path is set from the included filenames.php above (here under (includes/functions). The database.php file brings in functions that provide basic database routines like connecting (tep_db_connect), closing the db (tep_db_close) error checking (tep_db_error), executing a query with error logging (tep_db_query), inserting or updating (tep_db_perform), getting a row as an array (tep_db_fetch_array), getting number of rows in query (tep_db_num_rows) and other basic database-related operations. Next application_top uses one of these functions (tep_db_connect) to connect to the db. The next few lines get application and store parameters from the db. It uses two columns from the TABLE_CONFIGURATION (configuration table). This table in my db has 173 records with all of the store parameters in these two columns. A sample of the parameters include: store name, store owner, display cart after adding product (t or f), tax decimal places, list of payment modules installed, display shipping (t or f), default language... The list goes on and on. Each parameter is stored in a program constant that matches the configuration key from the db. The next few lines start to buffer output if gzip compression is enabled in the GZIP_COMPRESSION parameter from the previous db parameter access. The next section sets the HTTP Get parameters manually if search-engine_friendly_urls were enabled from the earlier db parameter access: if (SEARCH_ENGINE_FRIENDLY_URLS == 'true') It parses the "friendly" url into its constituent GET parameters and stores them in the $HTTP_GET_VARS php array. Next, application_top brings in functions used application-wide from two files (path to files: DIR_WS_FUNCTIONS dir set above): general.php and html_output.php. -----Begin Functions Imported by general.php: * tep_exit - exit and close session. Stop parsing. * tep_redirect - redirects to another page or site. * tep_parse_input_field_data - parses data and substitutes translated quotes to &quot; or whatever -- used in HTML tags so tags will not break. * tep_output_string - based on Boolean parameters, decides how to filter or parse data for safety. * tep_output_string_protected - runs the function above, making it filter out html special characters. * tep_sanitize_string - uses regular expressions to take out dangerous characters. (Author note: if could be done with simpler php functions, it would run faster.) * tep_random_select - runs a query that selects a random table row. Uses the database functions discussed above. * tep_get_products_name - returns a product's name from the products db table given the product's id. * tep_get_products_special_price - returns a product's special offer price if there is one given product id. * tep_get_products_stock - returns a product's stock from products table. * tep_check_stock - checks if required stock is available. If not, it returns an out of stock message. * tep_break_string - breaks a work in a string if it is longer than a length passed to the function. Separates with '-'. * tep_get_all_get_params - return HTTP get variables from previous page request. * tep_get_countries - returns an array with country info from the countries table. Same as an alias function, tep_get_countries_with_iso_codes, except this one forces it to get iso codes too. * tep_get_country_name - alias to tep_get_countries, but returns name without iso codes. * tep_get_path - generates a path to categories (parent) given a category id with a query to TABLE_CATEGORIES. * tep_browser_detect - returns whether the client's browser is the one passed to function. * tep_get_zone_code - returns the zone, state or province, code given a country id and a zone id. Queries TABLE_ZONES. * tep_round - rounds a number passed in as a string, given precision as a second parameter. Like the php function, round. * tep_get_tax_rate - Returns the tax rate for the customer's zone. Sets global variables for customer_zone_id and the customer_country_id. Then it does a query on tax_rates and zones_to_geo_zones tables to get the tax rate. * tep_get_tax_description - returns the tax description for a zone and class. Queries tables TABLE_TAX_RATES, TABLE_ZONES_TO_GEO_ZONES and TABLE_GEO_ZONES. If no description, returns text for TEXT_UNKNOWN_TAX_RATE. * tep_add_tax - adds tax to product's price and returns it. Takes the price and the tax returned by tep_calculate_tax. Also uses tep_round. * tep_calculate_tax - returns price multiplied by the tax rate and rounds with tep_round. * tep_count_products_in_category - returns the number of products in a category. It queries the tables products, products_to_categories and categories. * tep_has_category_subcategories - returns true if a category as id passed to function has any subcategories. It queries the categories table. * tep_get_address_format_id - returns an address_format_id for a country id passed to this function. It queries the table countries. * tep_address_format - takes an address and address format parameters and a format id and returns a formatted address. It can format the address as plain text or html. It also queries the table, address_format. * tep_address_label - This returns a formatted customer shipping address by retrieving the address from the db and passing it to tep_address_format. It queries tables customers and address_book. It calls tep_get_address_format_id and then tep_address_format. * tep_row_number_format - if a number is less than 10, it makes sure that it has a leading 0. * tep_get_categories - given parameter of a parent id and the parent ids of categories passed to it, it returns all of the categories under these parents. (Author note: This function is recursive and db intensive, and so probably could be rewritten for better performance.) * tep_get_manufacturers - selects and returns all of the manufacturers ids and names in an array through a query to the manufacturers table. * tep_get_subcategories - puts all subcategory ids for a parent id into a $subcategories_array, which is passed by reference and changed in the function. (Author note: this function is also recursive, so could be rewritten for better performance.) * tep_date_long - takes a parameter as a $raw_date string in a specific date-time format, then reformats it to the locale date using the php strftime function and the string formatting specified by the format constant DATE_FORMAT_LONG. I see this constant defined in english.php under the languages directory. This file gets included from a later line in the application_top.php file that reads "require (DIR_WS_LANGUAGES. $language .'.php');". We will get to that later in this document. * tep_date_short - This returns a raw data string in the selected locale date format. (Author note: this includes an ereg regular expression function that could be coded differently for speed.) * tep_parse_search_string - parses a search string into individual objects. Search string is passed in and &$objects is passed by reference and populated in the function. Actually $objects in an array of pieces or little words and strings. * tep_checkdate - validates a date for correct number of days in month - no Feb. 29 - that it is the right length, that it is the right format given a passed in $formatstring, etc. * tep_create_sort_heading - returns a table heading with sorting capabilities. This creates a big html string to return. It takes a text heading as a parameter and wraps a lot of html around it with sorting options. It calls a number of other tep functions. * tep_get_parent_categories - recursively goes through all categories ids passed in and puts all parent categories into categories array (passed in by reference). It queries on categories table. (Author's note: These recursive functions are elegant, but are also the most performance-expensive way to do it. Recoding with regular loops will make it run much faster. All of those stacked function calls are slooooow. Also, maybe the query could be rewritten so that it does not have to be run so many times - once for each function call.) * tep_get_product_path - takes product id as a parameter. It returns a category path to the product, getting the parents. (Author note: it calls the recursive function above, so also slow.) * tep_get_uprid - returns a product id ($uprid) with attributes. It concatenates a passed in product id with option-value pairs taken from an array $params of attributes that is also passed into the function. * tep_get_prid - inverse of the tep_get_uprid function above. Takes its return value, $uprid, as a parameter and returns the product id. * tep_customer_greeting - returns a customer greeting. Does not take any parameters. It takes the formatting string from the constant TEXT_GREETING_GUEST and puts logon and account information into it using the sprintf php function. This constant comes from the english.php (or german.php, etc.) The "require" that brings this file into application_top.php is described below. * tep_mail - the central email function that sends email as text or html using MIME. The mail server must be configured correctly and correctly referenced in the php.ini directives. The parameters that it takes are: $to_name - name of the recipient $to_email_address - email address for the recipient $email_subject - email subject $email_text - this may contain HTML $from_email_name - the name of the sender $from_email_address - email address of the sender This function instantiates an object called $message from the email class. The email class (see below) comes from the email.php file in the classes directory. It really does all the work; this tep function wrapper is short. The email classes in email.php and mime.php are "required" into application_top.php as described below. This function manipulates the $message object with these methods: $message->add_html, $message->add_text, $message->build_message, and $message->send. * tep_has_product_attributes - given a product id as a parameter, it returns a Boolean with true if product has any attributes. * tep_word_count - returns the number of times a specific word or character (passed in as a parameter) is present in a string. * tep_count_modules - returns a count of modules. A list of modules is passed in separated by ";". The function splits this into an array using the ";" as the separator, then checks whether each one is registered as a class in the $GLOBALS array, and then adds it to the count if it is. It then returns the count of the modules. * tep_count_payment_modules - Counts payment modules. Takes the MODULE_PAYMENT_INSTALLED, which is the list of installed modules taken from the configuration table in the database (see above). It passes it to tep_count_modules and then returns the result. * tep_count_shipping_modules - Counts shipping modules. Uses MODULE_SHIPPING_INSTALLED in the same way that MODULE_PAYMENT_INSTALLED was used in the previous function. * tep_create_random_value - returns a random value. Length is passed in as a parameter, then it uses tep_rand to produce a random alphanumeric string of the correct length. * tep_array_to_string - returns key value pairs from an array (input parameter) as a string. It separates the keys and values with a passed in $equal value or '=' as default and separates each pair with a passed in $separator or '&' as a default. * tep_not_null - Checks to see if an input $value is not empty or null. Returns true if not empty or null, false otherwise. * tep_display_tax_value - Returns the tax percentage $value with optional padded decimals. It takes a $value parameter as the tax percentage rate and a $padding parameter for padded decimals with the default as TAX_DECIMAL_PLACES taken earlier from the configuration db table. * tep_currency_exists - Returns a currency code or false. Takes a currency code, $code, as a parameter and queries the db table "currencies" to see if it is found. If it is, $code is returned, if not, false is returned. * tep_string_to_int - Takes a $string as a parameter and just recasts it as an integer: "return (int)$string;". (Author note: This is so simple that a function call that slows performance is not needed. Why not just use (int)$string instead of this function call?) * tep_parse_category_path - Parses and checks the category path -- category parents ($cPath). It takes $cPath as a parameter and explodes it into an array. It checks that the categories listed are unique and the category ids are integers. It returns an array of the unique category ids in the path. * tep_rand - returns a random value using $min and $max input parameters. It uses the php mt_rand function. * tep_set_cookie - is a wrapper, and directly calls the php function setcookie, which defines a cookie to be sent along with the rest of the HTTP headers. To input directly to setcookie, this function takes the cookie name, value, expire (UNIX timestamp for expiration), path (on server for which cookie will be available where '/' is the default indicating the entire domain), domain, and secure (whether it can only be sent over secure https connections, with a default of 0 for false). This function adds a check using tep_not_null on the domain, and if it is null it sets it as an empty string). * tep_get_ip_address - returns the ip address of the requesting client-user or the remote ip address making the request. * tep_count_customer_orders - Returns number of customer orders from database. It uses the customer id in a select query to the orders table. It counts and then returns the number of orders made for that customer. * tep_count_customer_address_book_entries - counts the number of address book entries for a customer. It does a select-query and a count of the total records in the address book table for a particular customer ID. * tep_convert_line_feeds - used instead of php function nl2br which inserts HTML newline tags before all new lines in a string. This function works with older versions of php. As parameters, it takes the line feed charters to replace (e.g. \n) and what to replace them with (e.b. <br />). -----End of Functions Imported by general.php -----Continue with Statements from application_top.php: Next, application_top.php brings in html_output.php with "require(DIR_WS_FUNCTIONS . 'html_output.php'); -----Begin Functions Imported by html_output.php: As the name suggests, this file contains functions that return strings of html to output. * top_href_link - The HTML href wrapper function for hyperlinks. It returns a URL string $link that will be used for the html url href. Parameters: $page - page where links will go $parameters $connection - default is 'NONSSL' $add_session_id - default is true. $search_engine_safe - default is true. Global variables used: $request_type $session_started $SID - the session id First, it uses tep_not_null to check that the $page exists. If not, it calls "die" and produces a page that says "Error, unable to determine the page link!" Now we begin building up the $link URL that this function will return. It checks for SSL or NONSSL using the $connection parameter. It then concatenates HTTPS_SERVER . DIR_WS_HTTPS_CATALOG to the link string (or the non https version of this). On my local install, the non-ssl version would be HTTP_SERVER = 'http://localhost' and DIR_WS_HTTP_CATALOG = '/catalog/'. (Remember, the constants are from configure.php.) So we are building up the first part of the link URL. Next it checks that the $parameters parameter with tep_not_null. If they are there, it concatenates them to the link string. Now (in a while loop) it removes any '&' or '?' chars from the end of $link. Then, if the session id is defined, or we move from different HTTP and HTTPS servers, we add the session ID to the $link URL. The SESSION_FORCE_COOKIE_USE must also not be sent to false. This is a store parameter set in the configuration table in the db with a default of false. (For a discussion of this parameter see: http://www..info/docs/english/e_security_and_privacy_p roposal.html . This reference says: The only common method that exists to prevent the session ID from appearing on the url at all is to force the usage of cookies for the web application. When SESSION_FORCE_COOKIE_USE is enabled and the client has cookies disabled, a page will be displayed in place of the above actions describing to the client in friendly terms that they should enable cookies on their browser in order to proceed.) This little section of code composes a string for the session ID in a variable $_sid, which it later concatenates to $link (the href url the function composes). If the conditions are met for appending the session ID to the url, then it checks to see if $SID is empty or null with tep_not_null. If so, it sets $_sid = $SID, the global session ID variable. If not it checks on a number of other conditions, and if met, gets the session name (tep_session_name) concatinated to '=' and a session id (tep_session_id). The next section in the tep_href_link function checks whether SEARCH_ENGINE_FRIENDLY_URLS (from the configuration db table) is true and if the $search_engine_safe parameter that was passed in is true. If so, then it replaces all '&&' with '&' and then all '&', '?' and '=' with '/' in the $link url. Finally, the function concatenates $link with $_sid (if it is set with a value) back into the $link variable. It then returns the $link string. * tep_image - This is the html image wrapper function. It compiles an entire "<img >" string in $image, which it returns. Parameters: $src - The image file source (src html tag for image) $alt - '' as default. The alt html tag for the image. $width - '' as default. Width of image for html. $height - '' default. Height of image. $parameters - '' as default. First, it returns a false if upon these conditions: $src (a parameter) is empty or set to just DIR_WS_IMAGES (image directory set in configure.php) AND IMAGE_REQUIRED (from the configuration db table) is 'false' (which is the default). Then $alt is added to the img tag even if it is null to prevent browsers from outputting the image filename as default. Here it starts composing the $image variable, which it will eventually return. It puts the html img tag in the string and concatenates the src border="0" and alt attributes. Then it concatenates "title =" &alt as an attribute. Now, if CONFIG_CALCULATE_IMAGE_SIZE (from db configuration table) is 'true' and the width and height are not set from the parameters then A php function gets the image size of the src file. It uses these results to set $width and $height, or, if $width OR $height were specified as parameters to this tep_image function, it makes sure $width and $height are BOTH set using the src image size if necessary. Then it concatenates the $width and $height to the $image string preceded by html attribute labels "width=" and "height=". Now, if $parameters were passed into the function, it concatenates them to the $image string. Finally, it closes the image string with '>'; and returns it from the function. * tep_image_submit - This is the html form submit button wrapper function. It outputs a button in the selected language. It composes and returns a string $image_submit for the html submit button. Parameters: $image - the file name of the submit button $alt - alt attribute for the image, '' is default $parameters - default is '' Global variable used: $language First, it composes an $image_submit string (the submit button html), which starts with "<input type='image' src =" then the language directory (DIR_WS_LANGUAGES . $language . '/images/buttons/') then $image (which, you have to assume, is the file name of the correct button in the correct language). Then it adds "border=0" and "alt =" followed by the $alt tag parameter passed to this function. (Author note: validation should have first tested $image to make sure that it existed as a valid image file in the correct directory.) Then the function adds 'title=' and the $alt parameter to $image_submit. It then checks if $parameters contains anything and adds them to $image_submit. The function then returns $image_submit. * tep_image_button - Outputs an html function button in the selected language. It uses the same parameters and global variable as tep_image_submit did above. It calls (and returns output from) tep_image, which composes an "<img" html tag with the appropriate $language leading to the correct language directory where it should find $image as the correct image button for that language. (See notes above on validation.) * tep_draw_separator - It outputs a separator either through white-space, or with an image. Parameters: $image - default is 'pixel_black.gif' $width - default is '100%' $height - default is '1' This function calls tep_image (and returns the results) with these parameters: 'DIR_WS_IMAGES . $image' for $src, '' for $alt, $width as passed to this function and $height as passed to this function. The image pixel_black.gif is just a black, onepixel shim. With the defaults, it just returns the html for a black line the width of the screen (or table cell). * tep_draw_form - returns a html form-start tag with attributes as a string. Parameters: $name - no default, so required $action - no default, so required $method - default is "post" $parameters - default is '' It contcatinates (and then returns) all of these start-form tag string-pieces: "<form name=> . $name . "action=" . $action . "method=" . $method . $parameters (if $parameters has some data) . ">". * tep_draw_input_field - returns a string with html for a form input field. Parameters: $name - no default, so required $value - '' for default $parameters - '' default $type - 'text' is default $reinsert_value - true is default It starts by concatenating string pieces into the variable $field as follows: "<input type=" . $type . "name=" . $name. It checks that $name is set as a global variable and $reinsert_value (see above parameter) is true. If this checks, then it concatenates (to $field) "value =" . $GLOBALS[$name], which is the global variable $name, not the parameter set above. If the check above evaluates to false, then instead it concatenated "value =" . $value. So this can display any value in the form field. It then concatenates any $parameters if they exist, adds the ending ">" and returns the $field string. * tep_draw_password_field - returns a string with a form field for a password. Parameters $name - no default $value - default '' $parameters - default maxlength="40" It calls tep_draw_input_field above with these parameters and 'password' for type, and returns the result. * tep_draw_selection_field - returns a string for a selection field. It is an alias for tep_draw_checkbox_field and tep_draw_radio_field. Parameters: $name - no default $type - no default $value - default '' $checked - default is false $parameters - default '' It begins by concatenating into a $selection variable: "<input type=" . $type . "name=" . $name. Then if there is a $value it adds "value=" $value. Then, if $checked == true or a bunch of other conditions it adds 'CHECKED'. Now, if there are $parameters, it concatenates them to $selection. Finally, it closes $selection with '>' and returns its value from the function. * tep_draw_checkbox_field - it just calls tep_draw_selection_field with the same parameters, except it sets $type as 'checkbox'. * tep_draw_radio_field - it just calls tep_draw_selection_fields with the same parameters, except it sets $type as 'radio'. * tep_draw_text_area_field - returns a string with a form textarea field. Parameters: $name - no default $wrap - no default $width - no default $height - no default $text - '' default $parameters - '' default $reinsert_value - default is true It begins by concatenating into a $field variable: "<textarea name=" . $name . "wrap=" . $wrap . "cols=" . $width . "rows=" . $height. Then it adds $parameters if there are any and adds a '>' to close the tag. Now, if $reinsert_value is true, it adds $GLOBAL[$name] to the string if it exists else, if $text has a value it adds that. Finally, it closes the $field string with </textarea> to finish this form field, and it returns the string value of $field. * tep_draw_hidden_field - returns a string for a form hidden field. Parameters: $name - no default $value - default '' $parameters - default '' It begins by concatenating into a $field variable: '<input type="hidden" name=' . $name. Then, if $value is set, it adds 'value=' . $value else if $GLOBALS[$name] is set it adds 'value=' . $GLOBAL['names']. If there are $parameters, it adds them, closes the tag with '>', and returns the string value of $field. * tep_hide_session_id - returns the session ID in a hidden field. The function takes no parameters. It does use global variables: $session_started and $SID. If $session_started is true and $SID has a value, then it calls (and returns the value from) tep_draw_hidden_field, above, with tep_session_name() as the $name and tep_session_id() as the value. * tep_draw_pull_down_menu - returns a string with a from, pulldown select menu. Parameters: $name - no default $values - no default, but expects an array of values $default - '' default $parameters - '' default $required - default is false It begins by concatenating into a $field variable: '<select name=' . $name. Then if there are $parameters, it adds them and adds a '>'. Now, it uses a for loop to increment $i for the number of values in the $values array. For each of these values it concatenates the following to $field: '<option value=' . $values[$i]['id']. (This specifies the data that will be sent back to the server for this field through GET or POST.) Within the loop, if the $values[$I]['id'] value equals to $GLOBALS[$name] (if its set), then it concatenates 'SELECTED' and a closing '>'. Still within the loop, it adds $values[$i]['text'] with some replacements for special characters in the string (" to &quot;, '\' to &#039; etc.). It also adds the close to the option as '</option>'. It does this for each option value in the $value array. It closes the menu form-field with '</select>' and, if $required is true, it tells the user it is a required field by adding the value of TEXT_FIELD_REQUIRED (defined in english.php or the other language configuration files. In my english.php, the value is defined as: '&nbsp;<span class="fieldRequired">* Required</span>'.) Finally it returns the value of $field. * tep_get_country_list - returns a string with an html pull-down list of countries. Parameters: $name - no default $selected - default '' $parameters - default '' The function will build the list of values for the menu in a $countries_array. (It is building the $values array that will be passed to $tep_draw_pull_down_menu.) The first element of this array, is a two field array with the 'id' key as '' and 'text' key as PULL_DOWN_DEFAULT (which in my english.php is defined as 'Please Select'). So it is setup up the top line of the menu. The function then assigns the output of tep_get_countries (getting countries from the db) into a $countries array. It then begins a for loop incrementing $i for the number of values in the $countries array (number of countries). It adds each element from $countries to the $countries_array as an array with the 'id' as $countries[$i]['countries_id'] and the 'text' as $countries[$i]['countries_name']. After it finishes the loop, it calls (and returns the value from) tep_draw_pull_down_menu with $name passed to $name in that function, $countries_array passed to $values, $selected passed to $default and $parameters passed to $parameters. It leaves false as the default for $required. -----End of Functions Imported by html_output.php -----Continue with Statements from application_top.php: The next two linee in application_top.php sets the cookie domain. Depending upon whether we have set $request_type as NONSSL or not, we set the variable $cookie_domain to HTTPS_COOKIE_DOMAIN or its HTTP counterpart (constants from configure.php). Then we set $cookie_path to an analogous constant from configure.php. Now, if USE_CACHE (from the configuration db table) is TRUE, then include the functions cache.php from the DIR_WS_FUNCTIONS (includes/functions directory). ------Begin Functions Imported by cache.php: * write_cache - writes out serialized data. The function uses the php function serialize() to serialize into variable $var and then store that variable in a file - $filename. Parameters &$var - can be changed for program; it is a reference $filename - name of file to write to first the function opens $filename as write (handle $fp). If it succeeds, it obtains a file lock. It then serializes the data from the passed in $var variable and writes it to the file with fputs. The function then releases the file lock, and closes the file. It returns a true for success. * read_cache - reads back in the serialized data in $filename. It fills $var using the php function unserialize(). Parameters: &$var $filename - name of file that has stored serialized data $auto_expire - default is false. First, $filename is assigned the full path of the file from DIR_FS_CACHE (path from configuration db table, set in mine to /tmp/) plus $filename. Then it initializes $success to false. If $auto_expire and $filename exists, then it checks to see if the age of the file is greater than $auto_expire. It it is, then function returns false. If not (file age okay), then it opens $filename as read to a handle ($fp). It reads the entire file into the string $szdata and then closes the file. It uses the php function unserialize on the data in $svdata and assigns the results to $var. It returns true for $success. Remember that $var is now available outside the function because it was a parameter passed by reference. * get_db_cache - This function saves cache output from the database into $filename. The function checks the cache for cached data in $filename or retrieves it from the database and saves it if the cache is not present. Parameters: $sql - no default. This is a string with the SQL query to execute if needed. &$var - variable to be filled with cache data, to be available outside function because it is passed by reference. $filename - name of cache file, no default $refresh - default false. If true, do NOT read from cache. First get_db_cache initializes $var to an array. It then checks if $refresh is true OR read_cache on $filename (see above) returns false. If true, then it did not get cache, so it will go to the database: it connects to the MySQL database "apachecon". It then queries the db with $sql (checking for error) and then loops over the results using tep_db_fetch_array. It assigns each record ($rec) to each element of the $var array. It then writes the $var array using write_cache (which serializes it) to $filename. * tep_cache_categories_box - caches the categories box, writing it to a file and returning the cached output as a string. Parameters: $auto_expire - default false $refresh - default false It also uses these global variables: $cPath (set later in application_top with $cPath = $HTTP_GET_VARS['cPath']; so $cPath is the category filename passed along as a GET variable). $language, $language_id, $tree, $cPath_array, $categories_string First, the function checks whether $refresh is true OR if the read_cache returns false with these parameters: $cache_output for $var, 'categories_box-' . $language . '.cache' . $cPath for $filename and the $auto_expire for this function as the read_cache $auto_expire parameter. If these conditions are true, then it runs ob_start(), which is the php function that turns on output buffering. It then includes the file from DIR_WS_BOXES (includes/boxes from configure.php) called categories.php. This file then goes into the output buffer. -----Begin Summary of categories.php: This is a file that defines and executes a long function called tep_show_category and creates an infoBox object. In tep_show_category, it populates some global data structures used in the category tree - $tree, $categories_string, and $cPath_array. It returns an html table row and col with this data in it. This file is included in index.php later from column_left.php, which is used to construct the left column of the page. This file will be discussed there, in a document on index.php, in detail. -----End Summary of categories.php -----Continue cache.php: Cache.php then assigns the contents of the output buffer (results of categories.php) to the variable $cache_output through the php function ob_get_contents. It then turns off output buffering with ob_end_clean. It writes this $cache_output to the file 'categories-box' . $language . '.cache' . $cPath. The function tep_cache_categories_box then returns $cache_output as a string. * tep_cache_manufacturers_box - caches the manufacturers box in the same way that the categories box was cached above. Parameters: $auto_expire - default false $refresh - default false Global variables: $HTTP_GET_VARS and $language First, it initialized $manufacturers_id to ''. Iff $HTTP_GET_VARS['manufactuers_id'] is set AND $HTTP_GET_VARS['manufacturers_id'] is not null (note the different spelling of manufacturers_id, which makes you wonder about this function), then assign $HTTP_GET_VARS['manufactuers_id'] to $manufacturers_id variable. Then go through the same testing and output buffering procedures with manufacturers.php in the DIR_WS_BOXES directory that the function above did with categories.php. Manufacturers.php is described in detail in the index.php document right after the discussion of categories.php. The function then writes the contents of the file, the output buffer, to 'manufacturers_box-' . $language . '.cache' . $manufacturers_id. It also returns this output from the function as a string. * tep_cache_also_purchased - caches the also purchased module like categories and manufacturers were cached. Parameters: $auto_expire - default false $refresh - false Global variables: $HTTP_GET_VARS, $language and $language_id This function uses the same technique as the two functions above to cache the output of FILENAME_ALSO_PURCHASED_PRODUCTS (also_purchased_products.php) to the file 'also_purchased-' . $language . '.cache' . $HTTP_GET_VARS['products_id']. It also returns this as a string from the function. -----End cache.php -----Continue with Statements from application_top.php: Next, application_top.php includes (require) the contents of shopping_cart.php from the DIR_WS_CLASSES (directory includes/classes set in configure.php). -----Begin shopping_cart.php This file brings in one class - shoppingCart. * class shoppingCart Variables: $contents, $total, $weight, $cartID, $content_type (This is not PHP 5, so ALL class variables are public.) Methods (details below): shoppingCart, restore_contents, reset, add_cart, update_quantity, cleanup, count_contents, get_quantity, in_cart, remove, remove_all, get_product_id_list, calculate, attributes_price, get_products, show_total, show_weight, generate_cart_id, get_content_type and unserialize. * method shoppingCart - the constructor. It just calls the reset method for this class. Reset is called without parameters, so $reset_database defaults to false and the customer's shopping cart records in the database are NOT deleted. The next method is out of order from the code sequence (restore_contents comes first), but it is described next because it is called by the constructor. * method reset - initializes class variables and optionally executes a SQL query that deletes items from the customer's shopping cart tables in the database Parameters: $reset_database = false, value when called from constructor Global variables: $customer_id First it initializes some object variables setting $this>contents to an empty array, $this->total to 0, $this->weight to 0 and $this->content_type to false. The use of these variables will be described in context below. It also unsets the $this->cartID for the object, and if there is a global session variable for cartID, it unregisters the session variable. * method restore_contents - (listed above reset method in the code) It inserts the current cart contents in the database if it is not found and it resets the stored cart information in an object variable ($this->contents). It takes no parameters. Global variables: $customer_id First it uses tep_session_is_registered (see below for the sessions.php functions) with the customer_id to see if a global session variable was initialized as customer_id. If not, the method ends and it returns false. Basically, it checks that the customer has session information saved. Next, it inserts the current cart contents into the database. It calls the php reset function (not the reset method for the object, so watch for name confusion) to reset the array pointer to the start of the $this->contents array. After that, it loops over each shopping cart product-item ($products_id) in the $this->contents array. Within the loop: It does the following test to see if product_id is in db: This test sets $qty to the quantity for the product and executes a product query which selects the product_id from the customers_basket table for that customer_id and the product_id from the $this->contents array. That query is used to check to see if no product_ids were returned (no match in db to contents array product id). If this test is false (no matching product_id): It does an insert query for that product's cart information. That query inserts customers_id, products_id, the quantity and the date added into the customers_basket table. Then, it checks to see if the $this->contents variable has attributes set for that product_id. If it does: It runs the php function reset (not the reset method in this class) to move the array pointer to the beginning for the contents array for the object. It then starts an inner while loop that loops over each attribute set in the contents array for that product_id. Within this while loop it: It executes an insert query into the customers_basket_attributes table for the attributes from the contents array - one loop iteration and insert for each attribute. Else, if the test above for a matching product_id finds a matching product_id: It does a query to update the quantity for the appropriate record in customers_basket. Now, the restore_contents method calls the object's reset method to reset the per-session cart contents, but not delete the cart contents in the database ($reset_database = false). Next, it executes a query that selects products_id and quantity from the customers_basket table where the customer id matches the global $customer_id. It then uses a while loop to fetch each row from the results. Within this while loop: It takes the product_id returned from the db and uses It to set the value of the corresponding product element from the $this->contents array to an array with 'qty' as the key and the quantity value from the db as the value. Still within the loop, it executes a select query for attributes products_options_id and products_options_value_id from the customers_basket_attributes table. Now, in an inner while loop over each row of the above select query: It sets the $this->contents array value for the appropriate product, and attribute to the products_options_value_id from the db select query. Finally, the method calls $this->cleanup, which is described directly below. * method cleanup - If no quantity for a product, it removes it from the $this->contents array and the database. Note: This method is shown out-of-order from the code listing because it is used at the end of the method documented above. It takes no parameters. It takes one global variable: $customer_id. First, it resets the array pointer for $this->contents to the beginning. Then, within a while loop it gets each $key from the contents array: For each $key (product) it tests whether the quantity is less than 1. If this test is true: It removes the element $this->contents[$key]. Then, if the customer_id is a valid global session variable (session running) it deletes the record for the product from the customers_basket table. It also deletes the appropriate product record from the customers_basket_attributes table. * method add_cart - adds a product and its attributes to the cart, both the database and the $this->contents object variable. Parameters: $products_id - no default $qty - default '1' $attributes - default '' $notify - default true Global variables: $new_products_id_in_cart and $customer_id First, it sets $products_id with tep_get_uprid (see above for general.php), which creates a string with the $products_id followed by its attributes. Next, if $notify == true, it sets the global variable $new_producst_in_cart to $products_id (passed in). Then it registers new_products_id_in_cart as a global session variable. If there is data in $this->in_cart($products_id) then: It runs the $this->update_quantity method to update the products quantity and attributes. Else It adds the array for $products_id to the array $this->contents. It also adds the quantity value to the $products_id element in the contents array. Now it inserts into the table customers_basket the customers_id, products_id, quantity and date added for the product in the basket. It then loops over the $attributes attay (a passed in parameter), and for each iteration: It puts the value for the attribute into the appropriate array (product_id/attributes) element in the object's contents array. Then if the customer has a session running, it inserts this information into the database to the customers_basket_attributes table. It inserts a record with the customer_id, products_id, products_options_id and product_options_value_id. The function then calls $this->cleanup. As a final statement, the function assigns a temporary unique ID to the order contents to prevent hack attempts during the checkout procedure. It runs its $this_generate_cart_id() method and assigns the results to $this->cartID. * method update_quantity - updates the quantity in the cart for the objects contents array and in the database. Parameters: $products_id - no default $quantity - default '' $attributes - default '' Globlal variable: $customer_id If $quantity is empty, it returns true and ends; nothing needs to be updated. Then, if still running, it updates the contents[$products_id] array with the quantity. Then it updates the database: It runs an update query to the customers_basket table that updates set_customers_basket_quantity to $quantity for the given customer and product id. If $attributes was passed in as an array, it loops over that array. For each iteration: It sets the appropriate element in $contents to the value from the $attributes array. Now, it runs an update query, writing to the customers_basket_attributes table values to products_options_value_id for the record for the appropriate customer_id, products_id and products_options_id. * method count_contents - returns an integer with the total number of items in the cart. It takes no parameters or global variables. Firsts, it initialized $total_items to 0. Then it loops over the elements in the $this->contents array. For each element, it applies the function get_quantity($product_id) (as defined directly below), adding in the quantity for that product. It keeps adding these to $total_items, and finally returns $total_items. * method get_quantity - returns the quantity in basket for a product. Parameters: $product_id - no default No global variables. If the products_id element of the $this->contents array is set, then it returns the quantity for that product from the contents array. Otherwise, it returns 0. * method in_cart - returns a boolean with true if product is in the cart. Parameters: $products_id - no default No global variables. It checks whether the $products_id element of the object's contents array is set. If so, it returns true., Otherwise, it returns false. * method remove - remove a product from the cart. Parameters: $products_id - no default It has one global variable: $customer_id. First it takes the product out of the contents array with "unset($this->contents[$products_id]);". Then it removes the product from the shopping cart in the database. It deletes it from the customers_basket and customers_basket_attributes tables. It then assigns a temporary unique ID to the order contents to prevent hack attempts during the checkout procedure using $this->generate_cart_id. * method remove_all - an alias for $this->reset with no parameters (so does not change db, only object variables). * method get_product_id_list - concatenates the product ids into a string. It has no parameters. It loops over the $this->contents array and concatenates each $products_id element into a $product_id_list string, separating each with a ','. When the loop is finished, it returns this string (cleaned up). * method calculate - calculates the total price and total weight for the basket with the object variables $this->total and $this->weight. Parameters: none First, it initializes $this->total = 0; and $this->weight = 0;. If $this->contents is not set as an array, it exits, returns a 0. Now it loops over each element high level element of $this->contents. This loop surrounds the rest of the entire function. The loop pulls out each $product_id from the contents array for each iteration. Within each iteration of this loop: It sets $qty as the quantity from contents. It then gets the product's price. It runs a select query and returns products_id, products_price, products_tax_class_id, and products_weight from the products table for the product_id retrieved for each element of the loop. It sets $prid as the product_id from the products table. It then uses tep_get_tax_rate to return $products_tax for the products_tax_class_id from the products table. It then assigns the products_price from the db to $products_price. It then assigns the products_weight from the db to $products_weight. Still within the loop for a product_id it executes a specials query with a slect to get specials_new_products_price from the specials table for that product id ($prid) with a status of 1. If that query returns any rows, it sets $specials to the array returned from tep_db_fetch_array for the specials query above. It sets $products_price as the specials_new_products_price from this array (and thus the db). It then adds the tax with tep_add_tax, and multiplies by the quantity for the product ($qty) and adds it to the running total of $this->total. It also adds to a running total of $this->weight by multiplying $qty by the $product_weight. These two operations are calculating the total price with tax and weight for the whole shopping cart object. Next it calculates the attributes price: If attributes are set in contents array for the products_id now in the loop iteration, it starts an inner loop over each $products_id-$attributes element from the contents array. Each iteration puts the values from contents into an $option (attribute option) and $value (attribute value). Within this inner loop, for each attribute for the product: It does a select query to get options_values_price and price_prefix from the products_attributes table for the current (iteration) of product_id and attribute option and attribute value. It fetches the results of the query into an array called $attribute_price. If the price_prefix element of this array (from query) is a '+'it adds the tax to the options_values_price and multiplies it by the $qty by the basket. It keeps adding this to the total for the basket ($this->total). If price_prefix not a '+', it subtracts this amount from the running total (same formulation as above, just using '-=' instead of '+='. * method attributes_price - returns the total price for all attributes for a product. Parameters: $products_id - no default First, it initializes $attributes_price to 0. Then if the attributes element for the $products_id is set in the object's contents array, it loops over the product_id and its attributes and assigns the attribute option id to $option and the attribute value id to $value for each iteration: Within the loop, it executes a select query for options_values_price and price_prefix from the products_attributes table for the appropriate product_id, attribute option and each value id. It fetches the query results into an array. If the price_prefix element of this array (from query) is a '+'it adds the options_value_price for the attribute to $attribute_price. If not, it subtracts it from $attribute_price. After the loop is finished, it returns $attribute_price. * method get_products - returns an array of product arrays, each with descriptive fields. It takes no parameters. It has one global variable: $languages_id. First, if $this->contents is not an array, it exists, returning false. Now, if it is still running, it initializes $products_array as an empty array. Then it starts a while loop that iterates over each high-level element of $this->contents and puts the first element into $products_id for each iteration. Within the loop, it does a select query and gets values from fields from the products table; it gets products_id, products_name, products_model, products_image, products_price, products_weight and products_tax_class_id. It does an inner join from the products table to the products_description table, where products_id in the products and products_id in the products_description_table both equal the products_id in the current iteration of the surrounding while loop. It also selects for the correct language for the product name using $languages_id to match in the product_description_table. It fetches the results into an array - $products, and sets $prid to the products_id. It also gets the product price from this fetched-array and assigns it to $products_price. It now does a "specials query" by doing a select from the specials table for the field specials_new_products_price where products_id is the current $prid and status = '1'. If a row is returned from the query, it fetches the array from this query into $specials. It then sets $products_price equal to the specials_new_products_price from this array (and db). Finally, it assembles an array of product information and assigns it to another element in the the larger $products_array (which contains all of the arrays, one for each product). Each product array in $products_array uses the variables in this loop iteration to assign the id, name, model, image, price, quantity, weight, final_price, tax_class_id and attributes. Finally, after the overall while loop finishes, the function returns all of the product information with "return $products_array;". * method show_total - runs the calculate method, returns the total price for the cart as $this->total. This is just a wrapper to calculate. It takes no parameters and has no global variables. * method show_weight - also runs the calculate method, but returns the total weight for the cart as $this->weight. Like the one above, this is a wrapper function. * method generate_cart_id - returns a random value. Parameters: $length - default 5 It just runs tep_create_random_value from general.php (see above). It calls it with two parameters: $length passed in or default from the parameter above and 'digits' as a second parameter. Digits just causes it to consider the whole string as numeric characters, and return just a string of numbers. * method get_content_type - Returns the content type for existance of attributes and other conditions. It takes no parameters and has no global variables. It begins by initializing $this->content_type to false. If DOWNLOAD_ENABLED (from the configuration table) == 'true' AND $this->count_contents > 0, then (count_contents was not an original class variable, so I'm not sure where we are adding it from). Loop over each high-level array element in the $this->contents array, pulling out the first value as $product_id to use within the loop: Now, an inner loop: Loop over each array in from the $products_id element for the key 'attributes'. Pull the second element, the attribute value id, as $value. Run a select query that returns a count as an aggregate value for a group: It uses an inner join on the tables products_attributes and products_attributes_download. It joins them where products_attributes_id fields are the same. It selects where the product_id is the one specified in the outer loop above, and the options_values_id is the $value specified in the inner loop. It gives a count of all the records returned as total, so the total number of attributes with this id for a given product in the cart. It fetches the results into an array, $virtual_check. If the 'total' for $virtual_check is > 0 then It checks the type of $this->content_type: If it is 'physical' it assigns 'mixed' to the object's content_type. It then returns $this->content_type, ending method execution. Else, it assigns 'virtual' to the object's content_type and returns it. Else if the 'total' is =< 0 then If $this->content_type is 'virtual', it assigns 'mixed' to content_type and returns it. Else, it assigns 'physical' to content_type. If the attribute for this product id was not set in the contents array then If $this->content_type is 'virtual' it retuns 'mixed'. Else it returns 'physical' for $this->content_type. Now, look at the first If DOWNLOAD_ENABLED... way above. If that condition there does not evaluate true, then Assign 'physical' to $this->content_type Finally return $this->content_type if this statement was not reached before. * method unserialize - sets a dynamic object variable-variable, $this->$key, where $key (a possibly new object variable) is taken out of an array, $broken. Parameters: $broken - no default No global variables. It loops over each element of the $broken array, where each of these elements is a sub-array. It takes the value from the 'key' element in the sub-array, and assignes that as the new object variable, $key, for $this->$key. If the type of the value assigned to this variable is NOT 'user function', then it assigns the value in 'value' from the sub-array to the dynamic variable $this->$key. This method made my head hurt. -----End shopping_cart.php -----Continue with Statements from application_top.php: The applicaton_top.php file next brings in navigation_history.php using require. -----Begin navigation_history.php This file contains one class: * class navigationHistory - Can create an object that holds the history of the user's navigation of pages and related get and post variables for each. Variables: $path and $snapshot. The $path variable or ($this->path for an instantiated object) holds elemets where each element is an array representing a main page (like index.php or product_info.php) that was accessed. These pages are stacked up in sequence in the array, and then removed (truncated) from the array when the user moves back to a higher-level page like index.php. Within the sub-array for each main page is a great deal of information, including the category path, etc. The following shows a var_dump($this->path) -- screen dump -of this array after I went to the index.php main page first, and then a product page. I navigated through a category, which is also encapsulated in the information: array(2) { [0]=> array(4) { ["page"]=> string(9) "index.php" ["mode"]=> string(6) "NONSSL" ["get"]=> array(2) { ["osCsid"]=> string(32) "ff1e3e230f13e7d15bf32544933da11f" ["cPath"]=> string(3) "1_8" } ["post"]=> array(0) { } } [1]=> array(4) { ["page"]=> string(16) "product_info.php" ["mode"]=> string(6) "NONSSL" ["get"]=> array(3) { ["osCsid"]=> string(32) "ff1e3e230f13e7d15bf32544933da11f" ["cPath"]=> string(3) "1_8" ["products_id"]=> string(2) "25" } ["post"]=> array(0) { } } } Notice that his path variable for the object also holds the get array with the session id and other parameters. The cPath holds the category path designation -- categories as number codes separated by "_". * method navigationHistory - constructor It just runs $this->reset() * method reset - reinitializes object level variables It initializes $path and $snapshot (see above) each to array(). * method add_current_page -- This adds or subtracts main pages (as arrays) from the object's path variable as the user navigates. It adds and subtracts from the $this->path array, as described above. I found this a tedious method to follow, and had to read it carefully before I could even give the short description above. It has so much nested logic. It is also not documented at all, so some description might be valuable. No parameters. Global variables: $PHP_SELF, $HTTP_GET_VARS, $HTTP_POST_VARS, $request_type, $cPath First, it initializes $set to true. (For-Loop) Next comes a for loop, which loops over $i from 0 to the number of elements in the $this->path array. (If-1)Within the loop it checks (If-1) It also checks that the object's path variable 'page' element == the base filename (without path prefix) for the file with this script (whatever the top page is that does the includes -- like index.php). (If-2)Then it checks to see if the global $cPath is set ($cPath is the category path or parent categories to current), and if yes, then (If-3)It checks that cPath was set in the object as $this->path[$i]['get']['cPath']. Some other method, or this method, must have set this before this tests true. Also see the method set_path_as_snapshot for this class. If this is true, then it does a "continue" to jump back up to the top of the for loop above. If-3 NOT TRUE, then (If-4) it tests to see if the $path element shown directly above is == $cPath. It it is, then it removes all elements from the $this->path array from $i+1, after this item to the end of the array -- truncates $path array. Also makes $set = 'false'. It now breaks out of the for loop. If If-4 NOT TRUE, then it does a for loop over each element of the 'cpath' element from the object's path array. It compares each element to each element in the global $cPath, and if they are not equal, it truncates the $this->path array after that element. It then makes $set = true. It then breaks out of this for loop AND the one above it. End of If-4 and If-3 Now, test for If-2 not true (global $cPath not set), It now truncates $this->path from the $i element in the top for loop. It also assigns $set = 'true',and then breaks out of the top for loop. End of If-2 and If-1. After this, it keeps looping over the for loop if has not hit a break, and when finished, continues at this point. Now, it tests $set == true. So what is $set (not documented in code)? Basically, its saying that the category path should be "set," or added to the $path array for the object. So, it adds a path array for the object to $this->path as an array with the first element as 'page' for the file name (no path) of the current page, the 'mode' as the request type (SSL or NONSSL), a 'get' element as the $HTTP_GET_VARS, so an array of all the get vars that have come to this page and a 'post' element to match the 'get' just described. The get or post array contains a large amount of information passed from the previous page, as shown above for the ["get"] elements from the var_dump($this->path). * method remove_current_page() - removes the last page entry, or high-level element from the $this->path array record of pages visited. It takes no paramaters. It uses one global variable: $PHP_SELF. It get the $last_entry_position as the array index in the object's path array variable. If the current 'page' element of the last entry in the path variable equals the filename of the current page, then it removes that page-element from the object's path array as follows: unset($this->path[$last_entry_postion]); * method set_snapshot - gets a snapshot of the current page in an array that looks like a high-level element in $this->path. Snapshot looks like one element from path, as shown above in the var_dump(). Parameters: $path - default '' Global variables: $PHP_SELF, $HTTP_GET_VARS, $HTTP_POST_VARE, $request_type. First it checks to see if $page parameter holds a passed-in array. If $page is an array, then it sets the elements of $this->snapshot (a class property) for the elemets 'page', 'mode', 'get' and 'post' equal to the same elements in the passed-in $page array parameter. If the $path parameter is not an array (the default ''), then it sets each element listed above as follows: 'page' as the name of the current page, 'mode' as the global $request_type (SSL or NONSSL), 'get' as the global $HTTP_GET_VARS array and 'post' as the global $HTTP_POST_VARS array. * method clear_snapshot - Just sets the snapshot property to an empty array (=array()). It has no parameters or global variables. * method set_path_as_snapshot - gets a past, history, array from $this->path to represent a page, and uses that to fill in the elements in $this->snapshot. Parameters: $history - default 0 No global variables used. First it assigns the length of the number of high-level elements in $this->path (pages visited) - 1 - $history. So $history takes us back to the $pos of a past page. Then it assigns each element of that array (element) from path to 'page', 'mode', 'get and 'post to $this->snapshot. * method debug - essentially does a var_dump to the screen of the path and snapshot object properties, using echo. Helps with debugging. Parameters: None Global vars: none It loops over each high-level element in $this->path, and then over each array element within the high-level (page) element, and echos all the key=>value pairs to the screen. Then it contatenates the elements of the snapshot property into a string and echos that to the screen. -----End navigation_history.php -----Continue with Statements from application_top.php: The applicaton_top.php file next brings in compatibility.php using require. -----Begin compatibility.php This file inserts code that creates functions and magic quotes that should be in the version of php being used. If the functions are not there, or magic quotes is turned off, it compensates by supplying replacements or work-arounds. It makes sure that all of the $HTTP_xxx_VARS are initialized. It contains (and calls) a function called do_magic_quotes_gpc if magic quotes are turned off. * function do_magic_quotes_gpc - recursively filters each $value in $HTTP_xxx_VARS. Parameter: &$ar (which is a passed in aray for a $HTTP_xxx_VARS) It recursively calls addslashes($value) for each value in the array to replicate the effect of magic quotes if they were turned off. -End function do_magic_quotes_gpc Now the code in compatibility creates an alternative array_splice function if it does not exist is the php version being used (if it is an old php version). Now the code creates a function for in_array if that does not exist in the current php code. Then it creates an alternative for array_reverse if that does not exist. Then it does the same with the functions constant, is_null, array_merge, is_numberic, array_slice, array_map, str_repeat and checkdnsrr. -----End compatibility.php -----Continue with Statements from application_top.php: The code in application_top then checks to see if the session_start php funciton exists (a current version of php). If it does NOT, the code defines constants for PHP_SESSION_NAME, PHP_SESSION_PATH, PHP_SESSION_DOMAIN and PHP_SESSION_SAVE_PATH. Also, if the session_start php function does NOT exist, the applicaton_top.php file brings in sessions.php from DIR_WS_CLASSES directory using include. -----Begin sessions.php from DIR_WS_CLASSES directory Generally, this file contains three class -- php3session, php3session_user and php3session_files and many functions. These are used only if the server is running php 3 and not php 4. Notice that this file is only included if an if statement in application_top.php shows that the session_start function does not exist. That function was released with php 4. This file also contains quite a few functions, including _session_create_id, _session_cache_limiter, _php_encode, _php_decode, _wddx_encode, _wddx_decode, session_set_save_handler, session_module_name, session_save_path, session_id, session_register, session_unregister, session_is_registered, session_encode, session_decode, session_start and session_destroy. A these function are replacements of what would be available as php functions in version 4. Because it is unlikely that a new developer will be using php 3, we will not go though this file in any detail (since it is only included if that old version is used). -----End sessions.php from DIR_WS_CLASSES directory -----Continue with Statements from application_top.php: The file applicaiton_top.php then brings in another file called sessions.php, this time from the include/functions (DIR_WS_FUNCTIONS) directory. It is brought in uncondionally, so the funcitons are used for php 4 and 3. -----Begin sessions.php from DIR_WS_FUNCTIONS First, it tests the constant STORE_SESSIONS. This constant is defined in the /includes/configure.php file. There is defined as empty '' for the default handler. It can also be set to 'mysql' when session data will be stored in the database. - Begin if STORE_SESSIONS == 'mysql' if $SESS_LIFE is not set properly, it sets it to 1440. * function _sess_open - just returns true Parameters: $save_path, $session_name. * function _sess_close - just returns true Parameteres: none * function _sess_read - uses the parameter $key to query the sessions table and return the session data. Parameters: $key - no default. It queries for the session data from the database for the $key and where the session has not expired. * function _sess_write - writes session data into the database using an update or insert query. Parameters $key - no default $val - no default (session information to write) Global variable: $SESS_LIFE It sets the $expiry time to the current time + the session life ($SESS_LIFE). The it does a select query with the session key, and counts the number of records for that key. It checks the count to see that session records already exist. If the session data exists, it uses an update query into the sessions table to update the record with the $expiry for the expiry field and the value (as the parameter $val). If the session data does not exist, it uses in insert query to add the record. * function _sess_destroy - deletes the session record from the database. Parameters: $key It does a query to delete the $key record from the session table. * function _sess_gc - deletes the session data from the session table where the expiry is less than the current time. Parameters: $key - no default No global variables. It performs the delete query based on time() and the value in the expiry field. Finally, before ending this section on mysql session saving, the file calls the php function set_save_handler with the functions above as parameters. This php function sets user-level session storage functions. For more information on this function, see http://us2.php.net/manual/en/function.session-set-save-handler.php - End if STORE_SESSIONS == 'mysql' * function tep_session_start - a wrapper for session_start. It runs that php function and returns the result. * function tep_session_register - a wrapper for the php session_register function, with a test on whether the session was started. If the session is started, it registers its passed-in parameter ($variable) as a global session variable. * function tep_session_is_registered - a wrapper for the php function session_is_registered. Parameter: $variable - no default It runs and returns the result for session_is_registered with $variable as the parameter. so, it tests whether that variable was registered as a session global variable. * function tep_session_unregister - just a wrapper for the php function, session_unregister. It takes a $variable as a paramater, and unregisters it as a session global variable. * function tep_session_id - wrapper for the php function, session_id. Parameter: $sessid - default '' If $sessid is not empty (not ''), then it runs session_id with the $sessid parameter, otherwise, it runs it with no parameters. This funciton either gets or sets the session id. * function tep_session_name - a wrapper for the php function session_name. Parameter: $name - default '' If $name is '', then it returns session_name($name), else it just runs session_name() without a parameter. So this sets or gets the current session name. * function tep_session_close - a wrapper for the php function session_write_close or session_close. It does not take any parameters. If the PHP_VERSION >= '4.0.4', then it runs session_write_close, else it runs session_close. It writes the session data and ends the session. * function tep_session_destroy - a simple wrapper for the php function session_destroy. * function tep_session_save_path - a wrapper for the php function session_save_path. Parameter: $path - default '' If $path is '', then return session_save_path($path), else return session_save_path() without a parameter. This sets or gets the current directory used to save the session data. * function tep_session_recreate - this function only does something if PHP_VERSION >= 4.1. It flushes, saves, deletes and recreates the session. If the php version >= 4.1, then it backs up the session information from $_SESSION global. Then it destroys the session, unsets the cookie name. If STORE_SESSIONS == 'mysql', it runs session_set_save_handler as described above for that condition. Then it starts the session again with tep_session_start. Finally it writes the saved temp variable holding the old $_SESSION back into $_SESSION. -----End sessions.php from DIR_WS_FUNCTIONS -----Continue with Statements from application_top.php: Finally, we get to use some of the functions from the other files, and not just include or require files. The following sections of code handles sessions. In application_top.php, we now set the session name and save path using tep_session_name and tep_session_save_path (see above). Now set the session cookie parameters: If the php function session_set_cookie_params exists, then use that, otherwise use the php function ini_set. Next, set the session ID if it exists: Call the tep_session_id function with the $HTTP_xxxx_VARS[tep_session_name()] as the parameters, depending upon whether GET or POST was used. Now, start the session: If the SESSION_FORCE_COOKIE_USE from the configuration db table is true, then check to see if a cookie was set. If so, use the tep_session_start function from above, elseif SESSION_BLOCK_SPIDERS is true from db, then check if it is a spider coming in. If not, then use tep_session_start to start the session. else start the session calling tep_session_start without parameters. Next, set the session ID - $SID with the constant SID or ''. Now verify the ssl_session_id if feature is enabled: Use the tep_session_register function with SESSION_SSL_ID as a parameter, and set a golbal var $SESSION_SSL_ID = to the session id from the global environment. If the session id is not registered in the global environment, then use tep_session_destroy to end the session and redirect the page output to FILENAME_SSL_CHECK (ssl_check.php from filenames.php config file). Next, verify the browser user agent if the feature is enabled: If true - SESSION_CHECK_USER_AGENT (from configuration table), which if true, validates the client's browser on every page request, then: set a global variable $http_user_agent and register the user agent with tep_session_register. Also (part of the above conditional), if the $SESSION_USER_AGENT is registered in the environment differently than $http_user_agent, then redirect the page to FILENAME_LOGIN. Now, verify the IP address if the feature is enabled: If SESSION_CHECK_IP_ADDRESS from db is true, then put the ip address from tep_get_ip_address into the global var $ip_address. If the session ip address is not registered (testing with tep_session_is_registered), then register it using tep_session_register. Still within the above conditional, if $ip_address is not registered then destroy the session and redirect to the FILENAME_LOGIN page. Next, create the shopping cart and fix the cart if necessary: pass 'cart' to tep_session_is_registered, and check that it is registered as a session variable and check that $cart is set as an object. If so, and PHP_VERSION < 4, then put the $cart data into a $cart object. If 'cart' not registered, then register it using tep_session_register and instantiate $cart as an object (new shoppingCart). Well, we knew we would be back to including the code from other files again, so here goes: Include currencies class and create an instance with a require for currencies.php using the path DIR_WS_CLASSES (includes/classes). -----Begin currencies.php from DIR_WS_CLASSES directory This file brings in one class to handle currencies, and uses the currencies table in the db. * class currencies - handles currencies class variables: $currencies, an array with currency info * method currencies - class constructor It does not take any parameters. First, it initializes $this->currencies to an empty array. Then, it does a select query on the currencies table for the fields code, title, symbol_left, symbol_right, decimal_point, thousands_point, decimal_places and value (exchange rate). It uses a loop to put each row from the query into the currencies array, where each high-level element in that array is one row from the database, and each element for each "row" represents the fields listed above. The field 'code' is used as the associative key for the high-level element. Basically, the array looks like the table in the db, where code (USD, EUR, etc.) is the "key" in the array (and currencies_id is the primary key in the table. * method format - returns a string, $format_string, with formatted currency conversions given the number passed in and the rate. Parameters: $number - no default $calculate_currency_value - default true $currency_type - default '' $currency_value - default '' Global variable: $currency First, if $currency_type is not passed in, set it to the global var $currency. The next section is conditional upon $calculate_currency_value == true. Now it sets the $rate to $currency_value or, if not passed in, then to the $this->currencies array value set for the object var in the constructor. First conversion: Then it gets down to business, and starts setting $format_string, which is the variable it will eventually return. It concatenates the currency left symbol (from object currencies array), the $number (a param) * $rate rounded, and then any currency symbols that follow. Now a section follows that accounts for this condition: If the selected currency is in the European euro-conversion and the default currency is euro, then the currency will display in the national currency and the euro-currency. It calls this function recursively to add this euro-currency (EUR appended to value). If the first condition ($calculate_currency_value == true) does not hold, it sets $format_string as in the "first conversion" paragraph above, but just returns $number, not multiplied by $rate. Finally, it returns $format_string. * method is_set - checks a passed in currency code to see if it is set in the object's currencies array. Parameters: $code - no default If $code is set as an element in the currencies array and is not null, then it returns true. Otherwise it returns false. * method get_value - returns the value from the currencies array for $code. Parameter: $code - no default It uses $code and 'value' as keys to $this->currencies to return the currency value for $code. * method get_decimal_places - returns the number of decimal places used for $code currency fromt the object's currencies array. Parameters: $code - no default Like the get_value above, but uses 'decimal_places' key instead of 'value'. * method display_price - adds tax, multiplies by $quantity and returns. Parameters: $products_price - no default $products_tax - no default $quantity - default of 1 Calls the format function above to create and return a formatted, currency converted, string for the price + tax * quantity. -----End currencies.php from DIR_WS_CLASSES directory -----Continue with Statements from application_top.php: Instantiate a currencies object (using class above) as $currencies. Now, applicaton_top.php brings in two email class files (mime.php and email.php) with requires. The class in email.php calls the methods from mime.php (which provides a supporting class). First it requires mime.php from DIR_WS_CLASSES (/includes/classes): -----Begin mime.php from DIR_WS_CLASSES directory This file brings in a class to assist in building mime-HTML emails. * class mime - One class in file for mime emails. Class variables: $_encoding, $_subparts, $_encoded, $_headers, $_body $_headers will hold a string of all the header info. $_subparts will hold an array of object instances of this class * method mime - constructor. Parameters: $body - no default. The body of the mame part, if any. $params - default ''. This is an associative array of parameters (array elements) as follows: content_type - For this part, e.g. multipart/mixed encoding - e.g. 7 bit, base64 or quoted-printable cid - content id to apply disposition - content disposition, inline or attachment dfilename - optional filename for content disposition description - content description First, make sure that the correct linefeed sequence is used. If EMAIL_LINEFEED (from configuration db table) == 'CRLF', then set an object variable $this->lf = "\r\n", else make it "\n". Now loop over each element in $params array and set HTML headers for the values in content_type, encoding, etc. This uses a array $headers which have 'Content-Type', 'Content-Transfer-Encoding', as keys to match the $params and the label for the header. First, set the content type element of headers to the matching $params element with extra text for the character set. Second, set the encoding element of $headers to the appropriate element of $params. Third, set the content id element of $headers to the appropriate element of $params enclosed in <>. Fourth, set the content disposition element of $headers to the $params value with "filename=" . $params element dfilename concatenated. Fifth, set the content description headers to the value in the $params element. Next bit sets a default content-type to 'text/plain' in $_headers (if that element is not set). Then initialize the member variable $this->encoded to an empty array. Now assign $this->_headers as the $headers array created above. Also assing $this->body as $body (a passed in parameter). The constructor ends here. * method encode - encodes and returns the email. It also stores it in the encoded member variable. It returns an associative array, $endoded, containing two elements, body and headers. The headers element is an indexed array. Parameters: None (Note, if you are not familiar with creating mime emails, you can read about it at http://www.zend.com/zend/spotlingt/index.php and click on "Sending MIME e-mail from PHP - Part 1". You can also review the material in the Zend Certification Guide on this subject.) First, assign $this->encoded to a method var, $encoded. Then, if the method var $_subparts is not null, then write a unique boundary string into the variable $boundary. Concatenate the boundary and the linefeed into content type element of $this->_headers. This member var will hold all the header information. Next, add body parts (poor wording, sorry) to $subparts array. Loop over all the elements (mime objects) in $this->_subparts Within that, loop over the elements of the 'headers' array for each object and put a string for "$key" . ":" . "$value" for the header into a method array, $headers. Within the top loop, implode all the body part info and header string into elements for a $subparts array. The loops end here. Then create an $encoded array element for 'body' that puts together the boundaries, subparts and line feeds. If $this_subparts was null, just put the $this->body info into $encoded[body] using the encoding method in $this->_encoding. Then add the headers to the 'headers' element of $encoded. It just assigns the member var $this->_headers to this element. Finally, return the array value of $encoded. * method &addSubPart (note that it returns a reference) It adds a subpart to the current mime part and returns the reference. Parameters: $body - no default. The body of the subpart, if any. $params - no default. The parameters for the subpart, which are the same as the $params argument set in with the constructor. This method returns a reference to the part just being added. The scripts calling this must use &= when calling this function, otherwise, they will not be able to add further subparts. It starts by adding a new mime object for the subpart to the $this->_subparts array. This array is used to compose the encoded version in the preceding method. It then returns the reference to the object - last mime subpart added. End &addSubPart method. * method _quotablePrintableEncode - Encodes the HTML msg to the quoted-printable standard. Parameters: $input - no default. The data to encode. $line_max - default of 76. An optional line max length. It should not be more than 76 chars. Frist, split $input into lines into an array, one line-element each per line in $lines. Split by end line characters. Next, loop over the $lines array for each $line. Within this, loop over each character in the line. Encode the character and concatenate it into a $newline var. End the inner loop. In the outer loop, concatenate each line to $output. Get rid of the last crlf. Return the value of $output. -----End mime.php from DIR_WS_CLASSES directory -----Continue with Statements from application_top.php: Just another file included for email: email.php brought in from DIR_WS_CLASSES directory. -----Begin email.php from DIR_WS_CLASSES directory This file brings in a class called email. This class also assists in building mime-HTML emails. It handles attachements and in-line images. * class email - builds html emails Member variables: $html, $text, $output, $html_text, $html_images, $image_types, $build_params, $attachments, $headers. They are not initialized here. (See reference under mime.php on learning mime email.) * method email - the constructor Parameters: $headers - default '' First, initialize $headers, $this->html_images and $this->headers as arrays. If EMAIL_LINEFEED from the configuration table in db is CRLF, then set lf member var to "\r\n", othersise "\n". If an auto load functionality is needed for other mime-image/file types, then the extensions and content type are added here. First add elements to member variable image_types array. For key 'gif', make value 'image/gif'. Do the same for jpg, jpeg, jpe, bmp, png, tif, fiff and swf. Set $this->build_params['html_encoding'] as 'quoted-printable', as default. Then, in same member var array, set 'text_encoding' to '7bit', 'html_charset' as 'CHARSET', a constant set in the english.php (or espanol.php, etc.) in the includes/languages directory. (See below.) For this array, set 'text_charset' to the same value. Then set 'text_wrap' to 998. Next, make sure the MIME version header comes first. Put 'MIME_Version: 1.0' as the first element of the headers array (member var). Then loop over the $headers array thay may have been passed into the constructor. Put each value into $this->headers[]. That is it for the constructor. * method get_file - This method will read a file in from a supplied filename and return it as a string. This string can then be given as the first argument of the functions add_html_image or add_attachment. Parameters: $filename - no default It opens the file and reads it into a string $return. It returns, $return with the file information. If it can't open the file, it returns false. * method find_html_images - This method extracts images from the html source. It will look through the html code supplied by add_html and find any file that ends in one of the extensions defined in the image_types member array var. If the file exists, it will read it in to the object to embed it with the email. Parameters: $images_dir - no default First, build the list of image extensions. Put them all into an array $extensions[]. Next, it matches a regex expression that includes an implode of $extensions to the string in $this->html. It puts alls the matches into the array $images. So it gets all of the image names in the $this->html file and puts them into $images. It then loops over the images (elements) in the $images array. It the file exists, it adds the name to $html_images[]. It then replaces the image name in the $this->html file with just the basename of the file (stripping out the directories the precede it). Then, if duplicate images are embedded, it removes them from $html_images so that they will not show up as attachements. It then sorts the $html_images image array. It then loops over all of the file names (elements) in $html_images and, after prepending the $images_dir passed in as a parameter, it uses get_file from this object to retrieve the contents of the image file into a string. It puts the string-file-contents into $image. It then returns the designation of the extension e.g. 'image/gif' for the extension, e.g. 'gif'. It then calls add_html_image from this object to save the image ($image string), the image name and its content type with the object. * method add_text - This adds plain text. This method is used when NOT sending html email. Parameters: $text - default '' It assigns the parameter $text to the $this->text member variable. * method add_html - It adds a html part to the email. It also replaces image names with content-id's. Parameters: $html - no default. The raw html part for the msg $text - default NULL $images_dir - default NULL It uses tep_convert_linefeeds to <br> in the $html file. It assigns it to $this->html. It uses the same function to replace line feeds in text with the "official" line feed from $this->lf. It stores the result into $this->html_text. It then calls find_html_images from this object, passing it the $images_dir passed in here. As described above, this method then extracts the images from the html source and adds the image file content to the object. * method add_html_image - called from find_html_images when it adds the image information to the object. It adds it to the html_images member array var. Parameters: $file - no default. This is the content of the image file. $name - default '' $c_type - default 'application/octet-stream' The function simply takes the passed in parameters and adds them to an array ('body' => $file, 'name' => $name, 'c_type' => $c_type and 'cid' is a unique id. It adds this array as an element to the $this->html_images array. * method add_attachment - Adds a file to the list of attachemnts. Parameters: $file - no default $name - default '' $c_type - default 'application/octet-stream' $encoding - default 'base64' It puts this information into the same type of array as used as elements in add_html_image. It then adds this array as an element to $this->attachements. * method &add_text_part - Adds a text subpart to a mime_part object. It returns a reference to the new mime object (See file above). Parameters: &$obj - no default. Mime object passed in by reference. Assigns 'text/html' to a $params['content_type']. Assigns 'html_encoding' from the build_params member var array to $params['encoding']. Does the same with 'html_charset' to 'charset' element of $params. It then calls the addSubpart method of the object (assuming that it is mime object), and it returns the results. If the $obj parameter passed in is not an object, it returns a new mime object with parameters $this->html and $params. * method &add_mixed_part - Starts a message with a mixed part mime type. Parameters: none. It assigns the string 'multipart/mixed' to 'content_type' element of $params. It then returns a new mime object, created with '' (no file) and $params. * method add_alternative_part - Adds an alternative part to a mime_part object. It returns a reference to the mime object. Parameters: &$obj - no default. A mime object (see above). First it assigns the string 'multipart/alternative' to the 'content_type' element of a $params array. Then, if $obj is set as an object, it assumes its a mime object and it returns the results (object reference) of its add_Subpart method with '' and $params for parameters. If $obj was not set, then it returns the reference to a new mime object with '' and $params as parameters. * method &add_related_part - Adds a html subpart to a mime_part object. Parameters: &$obj - no default. Should be a mime object This is just like the function above, add_alternative_part, except it makes the 'content_type' 'multipart/related'. * method add_html_image_part - This method adds a html image subpart to a mime_part object. Parameters: &$obj - no default. Assumes a mime object. $value - no default. An array with 'c_type', 'name', 'body' and 'cid' elements. In a $params array, it sets 'content_type' to 'c_type' from $value, 'encoding' to 'base64', 'disposition' to 'inline', 'dfilename' to 'name' from $value and 'cid' to 'cid' from $value. It then calls the addSubpart method for the mime $obj using $value['body'] and $params as the parameters. * method &add_attachment_part - It adds an attachment subpart to a mime object. Parameters: &$obj - no default. assumes a mime object $value - no default. An array of parameters In a $params array, it sets 'content_type' to 'c_type' from $value, 'encoding' to 'encoding' from $value, 'disposition' to 'attachment', 'dfilename' to 'name' from $value and 'cid' to 'cid' from $value. It then calls the addSubpart method for the mime $obj using $value['body'] and $params as the parameters. * method build_message - Builds the entire multipart message from the list $this->_parts. Parameters: $params - default ''. The message is shaped with $params, which is an array of parameters. The $params elements supported are: 'html_encoding' - The type of encoding to use on html. Valid options are "7bit", "quoted-printable" or "base64". The default is quoted-printable. 'text_encoding' - The type of encoding to use on plain text. Valid options are "7bit", "quoted-printable", or "base64". The default is 7bit. 'text_wrap' - The character count at which to warap 7bit encoded data. The default is 998. 'html_charset' - The character set to use for a html section. the default is iso-8859-1. 'text_chsrset' - The character set to use for a text section. The default is iso-8859-1. First it initializes $params to an empty array if it is an empty string. Then it loops over each element in $params, and assigns the keys and values to $this->build_params[$key] = $value. If the htem_images member var array has data, it loops over it. Inside this loop, for $this->html, the html message, it replaces each 'name' from html_images with "cid:" concatenated to 'cid' value from html_images. Then it initializes some imternal variables: - $attachements as true if the $attachments member var is not null, false otherwise. - $html_images to true if the $html_images member var contains data, false otherwise. - $html to true if the $html member var contains data. - $text to true if the $text member var contains data. Then it uses a switch-case for a set of conditionals the determines what mix of text, html and attachments need to be included: If $text == true and $attachments == false, it concatenates $this->text as a parameter to add_text_part and assigns the mime object reference to $message. If $text == false and $attachments == true and $html == false then it assigns the mime object reference from add_mixed_part method to $message. It then loops over the attachments listed in the $attachments member var and adds them to $message with the add_attachment_part method. If $text == true and $attachements == true it assigns the results of the add_mixed_part method to $message. It then runs the add_text_part method to add $this->text to the $message. Then it loops over all the attachements and adds them to the message. If $html == true and $attachments == false and $html_images == false, then it adds the $this->html_text to the message, and it runs html_add_part. If html_text does not have data, it just runs add_html_part. If $html == true and $attachments == false and $html_images == true, then it runs add_alternative_part and add_text_part for $this->html_text into the $message object. It then assigns the results of add_realted_part with the $message object to a variable $related. If the html_text member var is null or empty, then it assigns the object from add_related_part to $message and sets $related = $message. It then runs add_html_part method with the object in $related. Then it loops over all of the images in the html_images member array and assigns them with add_html_image_part to $related. If $html == true and $attachments == true and $html_images == false, then it puts the results of the add_mixed_part method into $message. If the $html_text member var is not empty, then it runs add_alternative_part with $message and assigns the results to $alt. It then runs add_text_part with $alt and the $html_text member var, and it runs the add_html_part method with $alt. If $html_text member var is null, then it just runs the add_html_part method with $message. Then it loops over all of the attachments and runs the method add_attachment_part with the parameters $message (the object) and the attachement from the member variable $attachements. If $html == true and $attachments == true and $html_images = true, then it assigns the results of the add_mixed_part method to $message. If the $html_text member var has data, then it assigns the results of add_alternative_part with the $message parameter to $alt. It then runs the add_text_part with $alt as the object parameter and the $html_text member var as the second parameter. It then runs add_related_part with $alt and assigns the results to $rel. If the $html_text member var has no data, then it runs add_related_part($message) and assigns results to $rel. It then runs add_html_part with $rel. It loops over all the images in the $html_images member var and adds them using $rel with add_html_image_part. Then it loops over all the attachments and adds them with add_attachment_part method. After these conditionals, it tests that $message is set and is an object. If it is, it uses its encode method and assigns the results to an $output array. It then takes the 'body' element from the $output array and assigns it to $this->output. Then it loops over all of the headers in the $output array, and puts them in a $headers array as concatenated $key and $value strings. Then it does an array_merge of $this->headers and $headers and returns true. If $message is not set and is not an object, it just returns false. * method send - Sends the email (finally) Parameters: $to_name - no default $to_addr - no default $from_name - no default $from_addr - no default $subject - default '' $headers - default '' (extra headers) First it concatenates the $to_name and $to_address with <> if address is there, and assigns it to $to. Then it does the same for "from" and assigns it to $from. If $headers is a string, it then explodes the passed in $headers string using its lf (end line) as delimiter, and passing the lines to elements of a $header array. It then loops over the elements of the $headers array and then (if each element of $headers is an array) it loops over each element of the header sub-array. It creates an array $xtra_headers with all of the elements. If each element of $headers is a string, it just adds them to $xtra_headers array. If the EMAIL_TRANSPORT (from the configuration table) is 'smtp', then it runs and returns from the php mail function with the to address, subject, $this->output as the message and all of concatenated header information. If the EMAIL_TRANSPORT is not 'smtp' (probably not Windows, but running a sendmail or sendmail emulator from Linux or Unix), then it calls the php mail function with the $to, $subject, $this->output and concatenated header info as parameters. End of send method. * method get_rfc822 - This method is used to return the email in message/rfc822 format. It is useful for adding an email to another email as an attachement. There is a commented out example in example.php. The method returns the email as a long string. Parameters: $to_name - no default $to_addr - no default $from_name - no default $from_addr - no default $subject - default '' $headers - default '' (extra headers) First it creates a date string for a header in RFC822 format. Then it concatenates the passed in parameters and strings to make the $to string. It does the same to make the $from string. If $subject is a string, it prepends 'Subject: ' to it. If $headers is a string, it explodes it into a $header array where the elements are lines. It puts all the elements in $headers (even if in sub-arrays), into a $xtra_headers array. Then it merges the $this->headers and $xtra_headers arrays. Finally, it returns a string for this email with all of the above elements concatenated together with line feeds ($this->lf) in the right places. -----End email.php from DIR_WS_CLASSES directory -----Continue with Statements from application_top.php: Ah, we get to return once again to application_top.php, and actually execute some statements there (other than includes). The next section of application_top.php sets the language configuration. These language constants are used in a number of the functions, classes and statements discussed above. At first, jumping down here to find the language constants was confusing (until I knew where to look). First, it uses tep_session_is_registered from above to check if 'language' is not set as a session variable or 'language' IS a returned GET variable in $HTTP_GET_VARS. Within this conditional, if 'language' is not a session varible, then it uses tep_session_register (see above functions) to register it. It also uses the same function to register 'languages_id' as a session variable. Still within this conditional, it includes the language.php file from the DIR_WS_CLASSES directory. -----Begin language.php from DIR_WS_CLASSES directory This file brings in one class -- language. * class language - defines general language related variables. Member variables: $languages, $catalog_languages, $browser_languages, $language (Be careful, don't confuse $language with $languages.) * method language - constructor, which is most of the class. Parameters: $lng - default '', the language code to set First it populates the $languages member variable with an array of language abbreviation codes (keys) with a longer pattern string with a longer description of the language. For example 'bg' is a key with a value of 'bg|bulgarian'. It then initializes the member variable $catalog_languages as an empty array. Then it does a db query to the languages table for its language_id, name, code, image and directory. It then fetches each row as an array and adds it to the $catalog_languages array with 'code' as the key and the other fields as values in a sub-array with keys 'id', 'name', 'image' and 'directory' The code then initializes the $browser_languages member variable to '' and the $language member var to ''. It then runs the set_language method (see below) with $lng, the constructor's parameter, as the parameter. * method set_language - Takes a $language as a parameter, and sets the $language (singular) member variable with the array from catelog_languages representing that particular language. Parameters: $language - no default If $lng for language was passed into the constructor, and if catalog_languages has an entry for that language, then assign that languages sub-array from the $catalog_languages member var array to the $language member variable array. Else use DEFAULT_LANGUAGE from the configurations db table as a key into the $this->catalog_languages array, and assign that sub-array to the $language member var. * method get_browser_language - gets the value of the environment variable HTTP_ACCEPT_LANGUAGE and uses that to set the $language member variable. Parameters: none It explodes the value of the above environment variable into an array and assigns it to the $browser_languages member variable. It then loops over the elements of this array, member variable, and within that it loops over each element in the $this->languages array (hard coded in constructor above). It searches the patterns and does an assignment of the browser language to a $key from the $languages member variable. It uses this key to the $this->catalog_languages variable and assigns the results to $this->language. It does not return anything, just sets a member variable. -----End languages.php from DIR_WS_CLASSES directory -----Continue with Statements from application_top.php: Now application_top.php instantiates a new language object (class shown directly above), as $lng. It does not pass a default $lng parameter to the object's constructor, and so takes the language from the database. Now, if a GET var as returned for 'language' and it was not null or empty, then the set_language method is run for the $lng object with the 'language' GET value as the parameter. Else it executes the get_browser_language method of $lng to set the language. It assigns the 'directory' element from the $lng->language array (parameters for set language) to a $language variable. It will use this variable shortly to create a dynamic file name (like english.php, where 'english' is the value of $language) for an include. It sets the 'id' from the $language member var to $languages_id. Now it brings in (requires) either english.php, espanol.php or german.php from the includes/languages directory. The first part of this file name is created using the $language variable defined above. As as example, (and because this is English, well sort of), we will use english.php as an example. -----Begin english.php from DIR_WS_LANGUAGES directory Every label, notice, message, etc. that needs to be shown in English (in this case) is included as a constant in this file. So, if you want to change a text label or message in the output, this is the place. As just one example: If you want to change "Top" to "Home", in the breadcrumb, go to the line: define('HEADER_TITLE_TOP', 'Top'); and change it there. Strangely, this file also has one function: * function tep_date_raw - takes a $date as mm/dd/yy and returns a string with either YYYYMMDD or DDMMYYY, depending upon whether a second parameter $reverse, is set to false (the default). So for false, it returns DDMMYYYY. -----End english.php from DIR_WS_LANGUAGES directory -----Continue with Statements from application_top.php: Now applicaton_top.php works directly with setting its $currency variable and its session variables related to currencies. If ('currency' is registered as a session variable (tested with tep_session_is_registered) or 'currency' is set as a returned GET varible) or (USE_DEFAULT_LANGUAGE_CURRENCY == 'true' from the configuration table in the db and LANGUAGE_CURRENCY (from english.php, or espanol.php...) != $currency) Then If 'currency' is not registed as a session variable, register it with tep_session_register('currency'). If the GET var was returned for 'currency' and if tep_currency_exists shows the currency does not exist (when it is then assigned to $currency), then if USE_DEFAULT_LANGUAGE_CURRENCY from db is true assign LANGUAGE_CURRENCY (from english.php) to $currency, else assign DEFAULT_CURRENCY (from db). The next section in application_top.php makes sure that the navigation history is registered as a session variable and saved in an object assigned First, test to see if the 'navigation' session variable is registered. If it is, and if PHP_VERSION<4, then put the contents of the global var $navigation into a temporary var, instantiate and save a new navigationHistory object and assign to $navigation, then unserialize the old, temp navigation variable using the $navigation object's unserialize method. This refreshes the navigation history. Else, register the 'navigation' session variable with tep_session_register. Assign an new navigationHistory object to $navigation. The next, long section of application_top.php makes sure that the shopping cart is set up and updated, if necessary. First, if 'action' is set as a GET var. . . This whole following section is predicated on this variable being set, which depends upon whether a form sets the 'action' using GET or POST. In my tests of the app, it appears that this section is not executed given my default configuration. One reason is that the default method in tep_draw_form function from html_output.php is set to 'post', not 'get'. But then this causes other login problems, so I would have to set some more parameters to get the GET passing to work properly and get this code section to execute. If 'action' is set as a GET var, then and a session has not been started (no cookies?) redirect the customer to a friendly, cookie-mustbe-enabled page (FILE_COOKIE_USAGE). If DISPLAY_CART == 'true', then set $goto var to FILENAME_SHOPPING_CART (shopping_cart.php). DISPLAY_CART is from the configuration table in the db. If true, it means: "Display the shopping cart after adding a product. False means to return back to the origin page." Set a $parameters var to an array of GET variable names that includes 'action', 'cPath', 'products_id' and 'pid'. If DISPLAY_CART is 'false', then set $goto to the base filename (without directories) of the current page being displayed, e.g. index.php. Then if the GET 'action' var equals 'buy_now', then set up $parameters as an array of GET var names, else set up $parameters without 'products_id', just 'action' and 'pid'. End if-section that tests DISPLAY_CART. Start switch-case. Now do a switch-case statement, testing the value of the 'action' GET variable. For this variable: Case 'update_product': It means that the customer wants to update the product quantity in their shopping cart. This condition is followed by half a page of code as follows: It loops over each element in the array from a 'produts_id' POST variable. Within this loop: If the element in 'products_id' is in the array for the POST var 'cart_delete', then it calls this method on the $cart object: $cart->remove( - the product_id element - ). So it removes it from the shopping cart object. If the element in 'products_id' in NOT in the 'cart_delete' it sets an $attributes variable equal to the attributes associated with the 'product_id' POST var. Then it runs a method on the $cart objects as follows: $cart->add_cart( -- see explanation -- ) Explanation of parameter: Passed in values for POST variable, 'products_id', 'cart_quantity', the $attributes array and false as a fourth parameter. It then redirects to the $goto page with tep_redirect and tep_get_all_params($parameters). Case 'add_product': The customer is adding a product from the products page. This section gets POST vars for product_id and uses them as parameters to $cart->add_cart method. Then it redirects to the $goto page. Case 'buy_now': if 'product_id' has attributes, it redirects to FILENAME_PRODUCT_INFO, else it runs the method $case->add_cart and redirects to the $goto page. Case 'notify': This is a pretty long section (half page), and its questionable when it would get executed, so I will defer doing pseudocode here until I understand its use. case 'cust_order': Goes though conditionals, then, if met runs $case->add_cart and then redirects to the $goto page. End section on shopping cart. Next, application_top.php includes the who's online functions from whos_online.php in the includes/functions directory -----Begin whos_online.php from DIR_WS_FUNCTIONS directory This file includes one function, which does an update or insert into the database showing information on this customer that is online. It also deletes old records from this table that are older than 900 seconds ago. So it shows information on customers recently online in the whos_online db table. * function tep_update_whos_online - See explanation above Parameters: none Global vars: $customer_id; Query the customers table for customer name for $customer_id of the current customer. Combine first and last into a $wo_full_name variable. If the customer_id is not a registered session variable, make $wo_full_name = 'Guest'; Save the session id, the ip address of the customer and the last requested page url into temporary variables $wo_session_id, $wo_ip_address, $wo_last_page_url. Store the current time and the time 900 sec ago. Use these time stamps, and run a delete query to remove old records from the whos_online table. Get a count of records, accesses, in the whos_online database for the current customer's session id. So this shows if there are currently entries in the db for this customer. If this count is > 0, then run an update query for the customer record in the whos_online table and update their name, ip_address, time of last click, last page url. Else, do an insert to add a record with this information for this customer. -----End whos_online.php from DIR_WS_FUNCTIONS directory -----Continue with Statements from application_top.php: Next, applicaton_top.php includes the password_funcs.php file from /includes/functions. -----Begin password_funcs.php from DIR_WS_FUNCTIONS directory This file brings in two functions that handle passwords. One validates a plain text password with an encripted one, and another makes a new encrypted password from a plain text password. * function tep_validate_password - Validates a plain text password with an encrypted password. Parameters: $plain - no default $encrypted - no default After checking that both parameters are passed in, it takes apart the $encrypted var into the hash and salt. It puts them into an array of two parts, breaking on the ":". It makes sure that there are two elements. It compares the md5 hash of the second element concatenating $plain. It compares that to the first element from the salt, and if they are equal, the function returns true. Otherwise, it returns false. * function tep_encrypt_password - takes a plain text password and returns an encrypted password, used as the salt in the function above. Parameters: $plain - no default It first uses tep_rand to fill the first 10 characters of a $password variable. Then it does an md5 of $password, and puts the first two chars into $salt. It then puts an md5 of the $salt concatenated to $plain, conacatenated to ":" and then concatenated to $salt. It returns this to later use as $encrypted for the validation in the previous function. -----End password_funcs.php from DIR_WS_FUNCTIONS directory -----Continue with Statements from application_top.php: Next, application_top.php includes validations.php functions. -----Begin validations.php from DIR_WS_FUNCTIONS directory This file loads one function, which validates an email address, and makes sure that it conforms to RFC 822 specs. * function tep_validate_email - See description above. It will return a true if its valid. Parameters: $email - no default (email to validate) It uses pretty exhaustive regex patterns to check email, whether it uses an ip address as a domain or a name. So first.last$[123.123.123.123] and first.last@host.com would be valid. It returns a true if the passed in email is valid, and false otherwise. -----End validations.php from DIR_WS_FUNCTIONS directory -----Continue with Statements from application_top.php: Next, application_top.php includes split_page_results.php -----Begin split_page_results.php from DIR_WS_CLASSES directory This file brings in one class -- splitPageResults. This class splits results of a query into multiple pages that can be navigated between using page nn button, next button, previous button, etc. * class splitPageResults - See preceeding explanation. Member variables: $sql_query, $number_of_rows, $current_page_number, $number_of_pages, $number_of_rows_per_page, $page_name * method splitPageResults - constructor Parameters: $query - no default. A SQL query that will give the display results. This is a string of the sql statement. $max_rows - no default $count_key - default '*' $page_holder = 'page' Global variables: $HTTP_GET_VARS, $HTTP_POST_VARS First, initialize $this->sql_query to the passed in $query. Second, it assigns $page_holder to $this->page_name. Then it checks whether GET or SET form variables were returned with the last request, and it sets $page to the appropriate value in $page_holder ('page') variable. If this does not work, it sets $page to '' and later 1. If it is not numeric, it also makes it 1. It sets $this->number_of_rows_per_page = $max_rows. After setting a lot of positions of substrings inside the $query, it does a query to get a count of the records, group by or distinct items using the "from" clause on from $query. It puts this count into $this->number_of_rows. It then assigns $this->number_of_pages by dividing number_of_rows by number_of_rows_per_page. If the $page number passed in is greater than the number_of_pages, then set $this->current_page_number = $this->number_of_pages. It then starts building a limit query using an $offset to get the bulk of the rows as a group that can be broken down into complete pages. It concatenates this to $this->sql_query. End of constructor. * method display_links - This displays split-page-number links. It returns a string of display links, such as: html <a href link to the current page with GET parameters and page number as well as labels from english.php (or other language file) with labels for the next page and next button. Parameters: $max_page_links - no default $parameters - default '' global variables: $PHP_SELF and $request_type (e.g. SSL) It adds an html link to the previous button for pages beyond the first page to $display_links_string. It creates an html link to jump to the previous set of $max_page_links. It creates links to jump to a page ($jump_to_page). It creates a hn html link to jump to the next window or group of pages. Then it adds a next button, with text from PREVNEXT_BUTTON_NEXT in english.php. Finally, it returns the $display_links_string. End display_links method. * method display_count - It displays the total number of products found for a page. Parameters: $text_output - no default. Generally this is the constant TEXT_DISPLAY_NUMBER_OF_PRODUCTS from english.php First it computes the to-number, $to_num as the number of rows per page * the current page number. Then if number of rows is greater, it sets $to_number to be number of rows. Then it gets the $from_num as the products on page. Then it composes and returns the $text_output, with the from, to and number of products values plugged into the string. -----End split_page_results.php from DIR_WS_CLASSES directory -----Continue with Statements from application_top.php: Now, application_top.php includes a file with a class for the input boxes. -----Begin boxes.php from DIR_WS_CLASSES directory This file contains a number of classes that represent screen boxes. The classes are tableBox, infoBox, infoBoxHeading, contentBox, contentBoxHeading, errorBox, productListingBox. These are very important classes that directly control output of screen elements (boxes) on all screens. * class tableBox - this is a parent class to infoBox and all the other boxes. It builds up the html in a string for the box display. * method tableBox - the constructor. It returns html for the basic table and contents for the box. Parameters: $contents - no default, a array of content elements $direct_output - default false First, it creates a method variable, $tableBox_string, that contains a html <table> start tag with attributes. Then, it loops over each element in $contents. If one of the elements is the content for a form, it concatenated that to $tableBox_string. Then it begins adds html for a table row tag into $tableBox_string. It adds parameters from member vars. Then it loops over each element in $contents, and adds a table cell "<td></td>" with attributes and contents. For each loope iteration it first adds a html table cell tag (<td>) with attributes. For each of iteration of the above loop, it adds the text contents from the $contents parameter, and then it closes the table cell with a "</td>". If the $contents element is not an array, it just makes one table cell "<td>" instead of multiple thourough a loop (as in the last paragrapy). As above, it adds html attributes from member vars then text, then it closes off the cell with "</td>". Now it ends the row tag "</tr>", still appending to $tableBox_string. It then ends the html form with "</form>". Finally it contatenates "</table>" to $tableBox_string to finish the table html for the box. It then tests the $direct_output passed in parameter, and if true, it echos all of the html from $tableBox_string directly to the browser secren. Finally, it returns the html string from $tableBox_string. End of constructor. There are no more methods for this class, so the class is basically the constructor and its member variables. End class tableBox. * class infoBox extends tableBox - Sets up an infobox. This class lets its paraent class, tableBox, do almost all of the work (see above). Member vars: only the ones inherited from the parent. * method infoBox - the constructor Parameters: $contents - array of html contents, no default First it builds up a local array, $info_box_contents, which it will use to finally pass as a parameter $content, when it calls the constructor of the parent, tableBox. So it sets up the parameters that tableBox uses to construct the html for the box. In this process, it calls the infoBoxContents method, below with the passed in $contents parameter. It then puts the results into a text element for the $info_box_contents array. Then it sets a member variable, $cell_padding to 1, instead of the tableBox default of 2. Then it adds a string 'class="infoBox"' as a parameter for a CSS attribute to put in through tableBox. Finally, it calls the constructor with an objected created by $info_box_contents as the $contents parameter, and true as a parameter to directly output the results of the tableBox constructor to the screen. End constructor. * method infoBoxContents - reformats the $contents array into a standard form that can be passed into the tableBox constructor for contents. Parameter: $contents - no default This method is called by the method above, and it reassigns the $contents elements into the proper array elements for passing to the tableBox constructor. It also adds separator html elements as array elements by calling tep_draw_seperator. Finally, it passes the reconsted array to the tableBox constructor to cast it into a string to put into an array element in the method above, which will then be passed back tableBox for final output to the screen. End infoBox class. * class infoBoxHeading extends tableBox - Creates heading for an infobox, set up as a box in its own right and output it directly to the screen. Member variables: only those inherited from the parent. * method infoBoxHeading - the constructor, which does all of the work for this class. Parameters: $contents - no default, an array $left_corner - default true $right_corner - deault true $right_arrow - default false Mostly, this puts in graphs for the rounded or stright corners at the top of infoboxes. It adds the references to the graphics files, and pulls them together into html (directly outpur) calling the constructor for tableBox. It also sets up other parameters for the heading, like a height of 14 (px) and references to CSS classes (class="infoBoxHeading") so that html referencs the CSS styles correctly. Note, we see the graphics that create the rounded or straight corners referenced here (so replace them if you want to change the look): They are all in the catalog/images/infobox directory as corner_left.gif corner_right_left.gif arrow_right.gif corner_right.gif * class contentBox extends tableBox - This will be instantiated outside of this file (in the file that directly outputs the html) to display the content of the infobox. Member variables: Only what it inherits from tableBox class. * method contentBox - constructor Parameter: $contents - no default It calls its other method, contentBoxContents using $contents as a parameter, to format the contents. It sets $this->table_cellpadding to 1 and sets a CSS reference to 'class="infoBox"'; Then it calls these parent tableBox constructor with the contents constructed here and a second parameter of true to send the output directly to the screen. * method contentBoxContents - adds parametrs and formats the $contents. Parameters: $contents This method is called from the contentBox constructor above. It sets the table_cellpadding to 4, and some html to reference CSS, 'class="infoBoxContenet"', and returns a string by calling $this->tableBox without outputting the results to the screen (just returning the html in a formatted string. * class contentBoxHeading extends tableBox - directly outputs the heading for the content box. * method contentBoxHeading - the constructor Member vars: just inherited from tableBox. First it sets table_width to 100% and table_cellpadding to 0. Then it creates a temporary array, $info_box_contents, where it puts html and references to infobox heading graphics (see above): corner_left.gif and corner_right.gif. It then calls tableBox, passing in the #info_box_contents as the contents, and passing true to output the results directly to the screen. * class errorBox extends tableBox - This just takes the contents passed to it, adds a CSS reference ('class="errorBox"'), calls its parent's construcor, tableBox, and output the results directly to the screen. * method errorBox - constructor. This does all of the actions describe above for the class. * class productListingBox extends tableBox - Another short class that does everything in a brief constructor and a call to its parent constructor. * method productListingBox - constructor It sets a CSS reference as 'class="productListing"'. It then calls tableBox constructor with its passed in $contents parameter, and a second param of true to send the output directly to the screen. -----End boxes.php from DIR_WS_CLASSES directory -----Continue with Statements from application_top.php: Next, applicaton_top.php includes banner.php -----Begin banner.php from DIR_WS_FUNCTIONS directory The functions in this file auto activate and expire banners. This is where that banner on the bottom with the graphic comes from. * function tep_set_banner_status - Sets the status of a banner. Parameters: $banners_id - no default $status - no default If the $status passed in is 1: It does an update query on the banners table where banners_id is the passed in parameter $banners_id. It updates status to 1, date_status_change to now(), and date_scheduled to NULL. If the $status is not 1, then it does an update query that sets status to 0, * function tep_activate_banners - Auto-activates banners Parameters: none It does a select query on the banners table where there is an entry for date_scheduled. It selects banners_id and date_scheduled from this table. Then it loops over each row (array), and if the current date is greater than the date in date_scheduled, it calls tep_set_banner_status (see above) to update the record in the database with a 1 status. * function tep_expire_banners - Expires banners by setting their status to 0 in table. Parameters: none It does a select query from the banners table joined to the banners_history table where status = 1, banners_id is the same in both tables (join field), and it groups by banners_id. It selects banners_id, expires_date and expires_impressions from banners and sums banners_shown form banners_history. It then loops over each row (as an array), and if today is greater than then expires_date, it sets the status in banners to 0. Else if the expires_impressions > 0 and the banners_shown >= expires_impressions, then it sets the status in banners to 0. * function tep_display_banner - displays a banner from the specified group or banned id (passed in $identifier) Parameters: $action - no default, should be 'static' or 'dynamic' $identifier - banner group to display If the $action == 'dynamic' then select from the banners table where status = 1 and the banners_group = $identifier that was passed in. Select banners_id, banners_title, banners_image and banners_html_text. Else return an error "No banners with group $identitier". If the $action == 'static' then run the same query describe directly above and put the results (one record) into a $banner array variable. Else return with an error. Then, after a little error checking, it sets a variable $banner_string as the 'banners_html_text' element of the $banner array. If there was no 'banners_html_text' in $banner, it puts a link with a redirect into $banner_string. Finally it returns $banner_string, which contains the html code for display. * function tep_banner_exists - it checks to see if a banner exists. Parameters: $action - no default, should be 'static' or 'dynamic' $identifier - banner group to display If the $action == 'dynamic', then it returns the results of a select query that selects from the banners table where status is 1 and the banners_group is $identifier. It selects banners_id, banners_image, banners_html_text. It uses the function tep_random_select to return a random row from this query. If $action == 'static' then it does a standard tep_db_query select from the banners table with the conditions for the query above. It fetches the row from the query, and returns it from the function as an array. * function tep_update_banner_display_count - updates the banner display statistics. Parameters: $banner_id It does a select query for a count of banner records in the banner_history table for the passed it $banner_id and the date is today. If this count > 0, then it does an update query for the banners_history table where the $banner_id is the one passed to this function. It sets banners_shown = banners_shown + 1. * function tep_update_banner_click_count - updates the banner click statistics Parameter: $banner_id It does an update query on banners_history table where the banner_id is the one passed to this function and the date is today. It adds 1 to banners_clicked. -----End banner.php from DIR_WS_FUNCTIONS directory -----Continue with Statements from application_top.php: Now application_top.php runs tep_activate_banners() and tep_expire_banners(). You cannot get rid of the banner by just commenting out these two lines. Now application_top.php includes specials.php -----Begin specials.php from DIR_WS_FUNCTIONS directory This file has functions that auto expire special products * function tep_set_specials_status -- updates special products in the specials db table. Parameters: $speicals_id - no default $status - no default It does an update query on the specials db table. It updates the row with the passed in $specials_id. It updates status to the passed in status, and the date_status_change to today. * function tep_expire_specials - expires specials in db table Parameters: none It does a select query to get the specials_id for the specials that have expired (now() > expires_date. It then passes those id's and a status to set of 0 to the function above. -----End specials.php from DIR_WS_FUNCTIONS directory -----Continue with Statements from application_top.php: The next statement in application_top.php runs tep_expire_specials (shown directly above), to expire specials in the database. Well, we get a few statements in the applicaiton_top.php now that do not just include other files: It now calculates the category path. If 'cPath' was passed to this from the last request as a GET parameter, then it sets a global variable $cPath to this GET parameter. Elseif 'products_id' was set as a GET varable but 'manufacturers_id' was not, then it sets $cPath to tep_get_product_path (see above) with the value of the 'products_id' parameter passed to it. If none of these are true, then $cPath = ''; Now, if $cPath is not null or empty, then use tep_parse_category_path (see above) on $cPath, and assign it to $cPath_array. Then implode $cPath_array into a string with '-' as separators between where the array elements were. Get the $current_category_id as the value in the top-most $cPath_array, else make $current_category_id to be 0. Well, we have only two more files to include, so hang in there. It next includes breadcrumb.php -----Begin breadcrumb.php from DIR_WS_CLASSES directory This file contains one class, breadcrumb, which sets up the breadcrumb trail. * class breadcrumb Member vars: $_trail * method breadcrumb - constructor Parameters: none It contains just one line which just runs the reset method below. * method reset - initializes $_trail array Parameters: none If initializes $this->_trail = an empty array * method add - adds a link to the breadcrumb in $_trail Parameters: $title - no default $link - default '' It adds an element to the _trail array, which is also an array with two elements. In that sub-array it sets 'title' to the value of the passed in $title, and it sets 'link' to the value of the passed in $link. * method trail Parameters: $separator - default '' First it initializes $trail_string to ''. Then it loops over each high-level element in the $_trail member variable array. It checks to see if the 'link' for that element is set and has data. If so, it concatenates a html link into $trail_string as an "<a href" tag with the link to the 'link' value in that $_trail element. It adds "class=headerNavigaton" for CSS styling and the 'title' from the $_trail element. It then closes the html with "</a>". If the conditional at the top of the preceeding paragraph is not true, then it sets $trail_string to the 'title' for the $_trail element. Before going back to the top of the loop, it adds the separator $separator into the $trail_string. Finally, it returns $trail_string -----End breadcrumb.php from DIR_WS_CLASES directory -----Continue with Statements from application_top.php: Now we get to execute about half a page of statements in applicaton_top.php to work with the breadcrumb trail. First it sets up a new breadcrumb object as, you guessed it, $breadcrumb. Now it build the breadcrumb. It runs the add method for $breadcrumb to add HEADER_TITLE_TOP ("top" in english.php) using the HTTP_SERVER for the link. Then it adds another -runnig add with HEADER_TITLE_CATELOG from english.php and calling tep_href_link on FILENAME_DEFAULT from filenames.php (index.php) to set the link. Then it adds category names or manufacturer names to the breadcrumb trail: If the $cPath_array is set, then it loops over each high-level element of $cPath_array. Within this loop, it does a query on the categories_description table. It selects on the categories_id from the $cPath_array element and the $languages_id. It selects the name of the category. It uses the category name from this query, and adds it (using $breadcrumb->add method) with the default filename and with a path added from the $cPath_array. If the $cPath_array is not set, then it checks that 'manufactureres_id' was set as a GET variable. If so, then it does a query to the manufacturers table for the manufacturers_name for that id. It adds that name to the breadcrumb with the appropriate html link tag and information. Now we add the products model to the breadcrumb trail. If 'products_id' is set as a GET var, then it selects the products_model field from the products db table for the 'products_id' Then we put that products_model value into the breadcrumb with the appropriate link. Well, time to include the last file, message_stack.php -----Begin message_stack.php from DIR_WS_CLASSES directory This file adds one class, messageStack, that initializes the stack for output messages. Code can later instantiate a $messageStack object, then do $messageStack->add('general', 'Error: Error 1', 'error'); to add an error message. It can then output it with $messageStack->output. * class messageStack extends tableBox - see explanation above. Mamber vars: none, other than what is inherited from tableBox and those created on the fly like messages. * method messageStack - constructor Global var: $messageToStack First, it initializes $this->messages as an empty array. Then, if 'messageToStack' is registered as a session var, it loops over each array element in $messageToStack. It uses $this->add method to add each element to the message stack. Then it unregisteres the 'messageToStack' session variable. End constructor. * method add - adds messages to stack Parameters: $class - no default $message - no default $type - default 'error' If $type == 'error', adds the message to the member $messages array, with an error.gif icon from DIR_WS_ICONS. It $type is 'warning' it does a parallel operation for that type. It does the same type of thing if $type = 'success'. Otherwise, it just adds the message to the stack. * method add_session - Registers the $message as a 'messageToStack' session variable. Parameters: $class - no default $message - no default $type - default 'error' Global vars: $messageToStack If the session var 'messageToStack' is not registered, then it registers it with tep_session_register. Then it puts the message with its class and type into the global $messageToStack array. * method reset - just reinitializes the messages member var array to an empty array. * method output - returns a string generated by tableBox constructor with the message in a textBox. Parameters: $class It creates a member variable $this->table_data_parameters on the fly here. it sets it equal to a CSS string to put into the html: 'class="messageBox". It then initialzes and begins creating an array $output to later pass to the tableBox constructor. It loops over all the elements of the $messages member var array. It makes sure fthat the 'class' element is set, and then puts the high-level element from $messages into the $output array. Finally it returns a string derived from calling the tableBox constructor using $output as the content parameter. * method size - returns a count of messages Parameters: $class - no default It loops over the messages in the $this->messages array, and if their 'class' element is set, it increments $count. After the loop, it returns $count. -----End message_stack.php from DIR_WS_CLASES directory -----Continue with Statements from application_top.php: The applicaton_top.php file now instantiates a new messageStack object called, $messageStack. Finally, it sets some constants for warnings that should be checked. These five constants start with "WARN_". You can read them at the end of the file. -----End mpplication_top.php from includes directory