home *** CD-ROM | disk | FTP | other *** search
/ 91.121.126.69 / 91.121.126.69.tar / 91.121.126.69 / www / osc / update-20051113.txt < prev   
Text File  |  2007-04-19  |  38KB  |  888 lines

  1. osCommerce 2.2 Milestone 2 Update 051113
  2. Update Package 13th November 2005
  3.  
  4. ------------------------------------------------------------------------------
  5. Table of Contents
  6. ------------------------------------------------------------------------------
  7.  
  8. ## Update 051113
  9.  
  10. customer_country_id in addressbook
  11.  
  12. ## Update 051112
  13.  
  14. Cannot re-assign $this
  15. limit -20, 20
  16. Database Input Enhancement
  17. Adding Non-Existing Products To Cart
  18. Session ID XSS Issue
  19. Validate Session ID
  20. File Manager Problem
  21. HTTP Header Injection
  22. E-Mail Header Injection
  23. Contact Us Form XSS Issue
  24. Open Redirector
  25. Extra Slashes In New Products
  26. Order Status Filtering
  27. MySQL 5.0 Compatibility
  28.  
  29. ------------------------------------------------------------------------------
  30. customer_country_id in addressbook
  31. http://www.oscommerce.com/community/bugs,1662
  32. ------------------------------------------------------------------------------
  33.  
  34. Problem:
  35.  
  36. When the customer updates their address in the My Account page, their country value is being stored in an incorrect variable that can cause an incorrect tax rate value being used in product prices.
  37.  
  38. Solution:
  39.  
  40. The following lines must be replaced in catalog/address_book_process.php:
  41.  
  42. Line 150, from:
  43.  
  44. $customer_country_id = $country_id;
  45.  
  46. to:
  47.  
  48. $customer_country_id = $country;
  49.  
  50. Line 171, from:
  51.  
  52. $customer_country_id = $country_id;
  53.  
  54. to:
  55.  
  56. $customer_country_id = $country;
  57.  
  58. ------------------------------------------------------------------------------
  59. Cannot re-assign $this
  60. http://www.oscommerce.com/community/bugs,1650
  61. ------------------------------------------------------------------------------
  62.  
  63. Problem:
  64.  
  65. Fatal error: Cannot re-assign $this in /path/to/catalog/admin/includes/classes/upload.php on line 31
  66.  
  67. Solution:
  68.  
  69. Lines 27-34 in catalog/admin/includes/classes/upload.php must be changed from:
  70.  
  71. if ( ($this->parse() == true) && ($this->save() == true) ) {
  72.   return true;
  73. } else {
  74. // self destruct
  75.   $this = null;
  76.  
  77.   return false;
  78. }
  79.  
  80. to:
  81.  
  82. if ( ($this->parse() == true) && ($this->save() == true) ) {
  83.   return true;
  84. } else {
  85.   return false;
  86. }
  87.  
  88. ------------------------------------------------------------------------------
  89. limit -20, 20
  90. http://www.oscommerce.com/community/bugs,1605
  91. ------------------------------------------------------------------------------
  92.  
  93. Problem:
  94.  
  95. 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-20, 20' at line 1
  96.  
  97. Solution:
  98.  
  99. Line 67 in catalog/includes/classes/split_page_results.php must be changed from:
  100.  
  101. $this->sql_query .= " limit " . $offset . ", " . $this->number_of_rows_per_page;
  102.  
  103. to:
  104.  
  105. $this->sql_query .= " limit " . max($offset, 0) . ", " . $this->number_of_rows_per_page;
  106.  
  107. Line 38 in catalog/admin/includes/classes/split_page_results.php must be changed from:
  108.  
  109. $sql_query .= " limit " . $offset . ", " . $max_rows_per_page;
  110.  
  111. to:
  112.  
  113. $sql_query .= " limit " . max($offset, 0) . ", " . $max_rows_per_page;
  114.  
  115. ------------------------------------------------------------------------------
  116. Database Input Enhancement
  117. ------------------------------------------------------------------------------
  118.  
  119. Problem:
  120.  
  121. Native MySQL functions should be used in preference to the addslashes() function, to properly protect the SQL queries being executed on the database server.
  122.  
  123. Solution:
  124.  
  125. The following function must be replaced in catalog/includes/functions/database.php.
  126.  
  127. Lines 126-128, from:
  128.  
  129. function tep_db_input($string) {
  130.   return addslashes($string);
  131. }
  132.  
  133. to:
  134.  
  135. function tep_db_input($string, $link = 'db_link') {
  136.   global $$link;
  137.  
  138.   if (function_exists('mysql_real_escape_string')) {
  139.     return mysql_real_escape_string($string, $$link);
  140.   } elseif (function_exists('mysql_escape_string')) {
  141.     return mysql_escape_string($string);
  142.   }
  143.  
  144.   return addslashes($string);
  145. }
  146.  
  147. The following function must be replaced in catalog/admin/includes/functions/database.php.
  148.  
  149. Lines 130-132, from:
  150.  
  151. function tep_db_input($string) {
  152.   return addslashes($string);
  153. }
  154.  
  155. to:
  156.  
  157. function tep_db_input($string, $link = 'db_link') {
  158.   global $$link;
  159.  
  160.   if (function_exists('mysql_real_escape_string')) {
  161.     return mysql_real_escape_string($string, $$link);
  162.   } elseif (function_exists('mysql_escape_string')) {
  163.     return mysql_escape_string($string);
  164.   }
  165.  
  166.   return addslashes($string);
  167. }
  168.  
  169. ------------------------------------------------------------------------------
  170. Adding Non-Existing Products To Cart
  171. http://www.oscommerce.com/community/bugs,1617
  172. ------------------------------------------------------------------------------
  173.  
  174. Problem:
  175.  
  176. It is possible to add non-existing products into the shopping cart which may prevent customers from removing the products from their cart.
  177.  
  178. Solution:
  179.  
  180. The following functions must be replaced in catalog/includes/functions/general.php.
  181.  
  182. Lines 912-921, from:
  183.  
  184. function tep_get_uprid($prid, $params) {
  185.   $uprid = $prid;
  186.   if ( (is_array($params)) && (!strstr($prid, '{')) ) {
  187.     while (list($option, $value) = each($params)) {
  188.       $uprid = $uprid . '{' . $option . '}' . $value;
  189.     }
  190.   }
  191.  
  192.   return $uprid;
  193. }
  194.  
  195. to:
  196.  
  197. function tep_get_uprid($prid, $params) {
  198.   if (is_numeric($prid)) {
  199.     $uprid = $prid;
  200.  
  201.     if (is_array($params) && (sizeof($params) > 0)) {
  202.       $attributes_check = true;
  203.       $attributes_ids = '';
  204.  
  205.       reset($params);
  206.       while (list($option, $value) = each($params)) {
  207.         if (is_numeric($option) && is_numeric($value)) {
  208.           $attributes_ids .= '{' . (int)$option . '}' . (int)$value;
  209.         } else {
  210.           $attributes_check = false;
  211.           break;
  212.         }
  213.       }
  214.  
  215.       if ($attributes_check == true) {
  216.         $uprid .= $attributes_ids;
  217.       }
  218.     }
  219.   } else {
  220.     $uprid = tep_get_prid($prid);
  221.  
  222.     if (is_numeric($uprid)) {
  223.       if (strpos($prid, '{') !== false) {
  224.         $attributes_check = true;
  225.         $attributes_ids = '';
  226.  
  227. // strpos()+1 to remove up to and including the first { which would create an empty array element in explode()
  228.         $attributes = explode('{', substr($prid, strpos($prid, '{')+1));
  229.  
  230.         for ($i=0, $n=sizeof($attributes); $i<$n; $i++) {
  231.           $pair = explode('}', $attributes[$i]);
  232.  
  233.           if (is_numeric($pair[0]) && is_numeric($pair[1])) {
  234.             $attributes_ids .= '{' . (int)$pair[0] . '}' . (int)$pair[1];
  235.           } else {
  236.             $attributes_check = false;
  237.             break;
  238.           }
  239.         }
  240.  
  241.         if ($attributes_check == true) {
  242.           $uprid .= $attributes_ids;
  243.         }
  244.       }
  245.     } else {
  246.       return false;
  247.     }
  248.   }
  249.  
  250.   return $uprid;
  251. }
  252.  
  253. Lines 925-929, from:
  254.  
  255. function tep_get_prid($uprid) {
  256.   $pieces = explode('{', $uprid);
  257.  
  258.   return $pieces[0];
  259. }
  260.  
  261. to:
  262.  
  263. function tep_get_prid($uprid) {
  264.   $pieces = explode('{', $uprid);
  265.  
  266.   if (is_numeric($pieces[0])) {
  267.     return $pieces[0];
  268.   } else {
  269.     return false;
  270.   }
  271. }
  272.  
  273. The following functions must be replaced in catalog/includes/classes/shopping_cart.php.
  274.  
  275. Lines 78-108, from:
  276.  
  277. function add_cart($products_id, $qty = '1', $attributes = '', $notify = true) {
  278.   global $new_products_id_in_cart, $customer_id;
  279.  
  280.   $products_id = tep_get_uprid($products_id, $attributes);
  281.   if ($notify == true) {
  282.     $new_products_id_in_cart = $products_id;
  283.     tep_session_register('new_products_id_in_cart');
  284.   }
  285.  
  286.   if ($this->in_cart($products_id)) {
  287.     $this->update_quantity($products_id, $qty, $attributes);
  288.   } else {
  289.     $this->contents[] = array($products_id);
  290.     $this->contents[$products_id] = array('qty' => $qty);
  291. // insert into database
  292.     if (tep_session_is_registered('customer_id')) tep_db_query("insert into " . TABLE_CUSTOMERS_BASKET . " (customers_id, products_id, customers_basket_quantity, customers_basket_date_added) values ('" . (int)$customer_id . "', '" . tep_db_input($products_id) . "', '" . $qty . "', '" . date('Ymd') . "')");
  293.  
  294.     if (is_array($attributes)) {
  295.       reset($attributes);
  296.       while (list($option, $value) = each($attributes)) {
  297.         $this->contents[$products_id]['attributes'][$option] = $value;
  298. // insert into database
  299.         if (tep_session_is_registered('customer_id')) tep_db_query("insert into " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " (customers_id, products_id, products_options_id, products_options_value_id) values ('" . (int)$customer_id . "', '" . tep_db_input($products_id) . "', '" . (int)$option . "', '" . (int)$value . "')");
  300.       }
  301.     }
  302.   }
  303.   $this->cleanup();
  304.  
  305. // assign a temporary unique ID to the order contents to prevent hack attempts during the checkout procedure
  306.   $this->cartID = $this->generate_cart_id();
  307. }
  308.  
  309. to:
  310.  
  311. function add_cart($products_id, $qty = '1', $attributes = '', $notify = true) {
  312.   global $new_products_id_in_cart, $customer_id;
  313.  
  314.   $products_id_string = tep_get_uprid($products_id, $attributes);
  315.   $products_id = tep_get_prid($products_id_string);
  316.  
  317.   if (is_numeric($products_id) && is_numeric($qty)) {
  318.     $check_product_query = tep_db_query("select products_status from " . TABLE_PRODUCTS . " where products_id = '" . (int)$products_id . "'");
  319.     $check_product = tep_db_fetch_array($check_product_query);
  320.  
  321.     if (($check_product !== false) && ($check_product['products_status'] == '1')) {
  322.       if ($notify == true) {
  323.         $new_products_id_in_cart = $products_id;
  324.         tep_session_register('new_products_id_in_cart');
  325.       }
  326.  
  327.       if ($this->in_cart($products_id_string)) {
  328.         $this->update_quantity($products_id_string, $qty, $attributes);
  329.       } else {
  330.         $this->contents[$products_id_string] = array('qty' => $qty);
  331. // insert into database
  332.         if (tep_session_is_registered('customer_id')) tep_db_query("insert into " . TABLE_CUSTOMERS_BASKET . " (customers_id, products_id, customers_basket_quantity, customers_basket_date_added) values ('" . (int)$customer_id . "', '" . tep_db_input($products_id_string) . "', '" . (int)$qty . "', '" . date('Ymd') . "')");
  333.  
  334.         if (is_array($attributes)) {
  335.           reset($attributes);
  336.           while (list($option, $value) = each($attributes)) {
  337.             $this->contents[$products_id_string]['attributes'][$option] = $value;
  338. // insert into database
  339.             if (tep_session_is_registered('customer_id')) tep_db_query("insert into " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " (customers_id, products_id, products_options_id, products_options_value_id) values ('" . (int)$customer_id . "', '" . tep_db_input($products_id_string) . "', '" . (int)$option . "', '" . (int)$value . "')");
  340.           }
  341.         }
  342.       }
  343.  
  344.       $this->cleanup();
  345.  
  346. // assign a temporary unique ID to the order contents to prevent hack attempts during the checkout procedure
  347.       $this->cartID = $this->generate_cart_id();
  348.     }
  349.   }
  350. }
  351.  
  352. Lines 110-127, from:
  353.  
  354. function update_quantity($products_id, $quantity = '', $attributes = '') {
  355.   global $customer_id;
  356.  
  357.   if (empty($quantity)) return true; // nothing needs to be updated if theres no quantity, so we return true..
  358.  
  359.   $this->contents[$products_id] = array('qty' => $quantity);
  360. // update database
  361.   if (tep_session_is_registered('customer_id')) tep_db_query("update " . TABLE_CUSTOMERS_BASKET . " set customers_basket_quantity = '" . $quantity . "' where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products_id) . "'");
  362.  
  363.   if (is_array($attributes)) {
  364.     reset($attributes);
  365.     while (list($option, $value) = each($attributes)) {
  366.       $this->contents[$products_id]['attributes'][$option] = $value;
  367. // update database
  368.       if (tep_session_is_registered('customer_id')) tep_db_query("update " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " set products_options_value_id = '" . (int)$value . "' where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products_id) . "' and products_options_id = '" . (int)$option . "'");
  369.     }
  370.   }
  371. }
  372.  
  373. to:
  374.  
  375. function update_quantity($products_id, $quantity = '', $attributes = '') {
  376.   global $customer_id;
  377.  
  378.   $products_id_string = tep_get_uprid($products_id, $attributes);
  379.   $products_id = tep_get_prid($products_id_string);
  380.  
  381.   if (is_numeric($products_id) && isset($this->contents[$products_id_string]) && is_numeric($quantity)) {
  382.     $this->contents[$products_id_string] = array('qty' => $quantity);
  383. // update database
  384.     if (tep_session_is_registered('customer_id')) tep_db_query("update " . TABLE_CUSTOMERS_BASKET . " set customers_basket_quantity = '" . (int)$quantity . "' where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products_id_string) . "'");
  385.  
  386.     if (is_array($attributes)) {
  387.       reset($attributes);
  388.       while (list($option, $value) = each($attributes)) {
  389.         $this->contents[$products_id_string]['attributes'][$option] = $value;
  390. // update database
  391.         if (tep_session_is_registered('customer_id')) tep_db_query("update " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " set products_options_value_id = '" . (int)$value . "' where customers_id = '" . (int)$customer_id . "' and products_id = '" . tep_db_input($products_id_string) . "' and products_options_id = '" . (int)$option . "'");
  392.       }
  393.     }
  394.   }
  395. }
  396.  
  397. ------------------------------------------------------------------------------
  398. Session ID XSS Issue
  399. http://www.oscommerce.com/community/bugs,1546
  400. ------------------------------------------------------------------------------
  401.  
  402. Problem:
  403.  
  404. A cross site scripting issue exists with malformed session IDs being used in the tep_href_link() function.
  405.  
  406. Solution:
  407.  
  408. Line 66 in catalog/includes/functions/html_output.php must be changed from:
  409.  
  410. $link .= $separator . $_sid;
  411.  
  412. to:
  413.  
  414. $link .= $separator . tep_output_string($_sid);
  415.  
  416. ------------------------------------------------------------------------------
  417. Validate Session ID
  418. ------------------------------------------------------------------------------
  419.  
  420. Problem:
  421.  
  422. Validate the session ID and redirect to the front page when an invalid session ID is requested.
  423.  
  424. Solution:
  425.  
  426. The following function must be replaced in catalog/includes/functions/sessions.php.
  427.  
  428. Lines 66-68, from:
  429.  
  430. function tep_session_start() {
  431.   return session_start();
  432. }
  433.  
  434. to:
  435.  
  436. function tep_session_start() {
  437.   global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS;
  438.  
  439.   $sane_session_id = true;
  440.  
  441.   if (isset($HTTP_GET_VARS[tep_session_name()])) {
  442.     if (preg_match('/^[a-zA-Z0-9]+$/', $HTTP_GET_VARS[tep_session_name()]) == false) {
  443.       unset($HTTP_GET_VARS[tep_session_name()]);
  444.  
  445.       $sane_session_id = false;
  446.     }
  447.   } elseif (isset($HTTP_POST_VARS[tep_session_name()])) {
  448.     if (preg_match('/^[a-zA-Z0-9]+$/', $HTTP_POST_VARS[tep_session_name()]) == false) {
  449.       unset($HTTP_POST_VARS[tep_session_name()]);
  450.  
  451.       $sane_session_id = false;
  452.     }
  453.   } elseif (isset($HTTP_COOKIE_VARS[tep_session_name()])) {
  454.     if (preg_match('/^[a-zA-Z0-9]+$/', $HTTP_COOKIE_VARS[tep_session_name()]) == false) {
  455.       $session_data = session_get_cookie_params();
  456.  
  457.       setcookie(tep_session_name(), '', time()-42000, $session_data['path'], $session_data['domain']);
  458.  
  459.       $sane_session_id = false;
  460.     }
  461.   }
  462.  
  463.   if ($sane_session_id == false) {
  464.     tep_redirect(tep_href_link(FILENAME_DEFAULT, '', 'NONSSL', false));
  465.   }
  466.  
  467.   return session_start();
  468. }
  469.  
  470. ------------------------------------------------------------------------------
  471. File Manager Problem
  472. http://www.oscommerce.com/community/bugs,1391
  473. ------------------------------------------------------------------------------
  474.  
  475. Problem:
  476.  
  477. Parsing errors occur when saving edited files through the File Manager.
  478.  
  479. Solution:
  480.  
  481. Line 148 in catalog/admin/file_manager.php must be changed from:
  482.  
  483. $file_contents = htmlspecialchars(implode('', $file_array));
  484.  
  485. to:
  486.  
  487. $file_contents = addslashes(implode('', $file_array));
  488.  
  489. Note: This update also requires the Contact Us Form XSS Issue update in order to function correctly.
  490.  
  491. ------------------------------------------------------------------------------
  492. HTTP Header Injection
  493. ------------------------------------------------------------------------------
  494.  
  495. Problem:
  496.  
  497. By using malicious data it is possible to inject headers into HTTP requests. 
  498. Solution:
  499.  
  500. The following function must be replaced in catalog/includes/functions/general.php.
  501.  
  502. Lines 22-32, from:
  503.  
  504. function tep_redirect($url) {
  505.   if ( (ENABLE_SSL == true) && (getenv('HTTPS') == 'on') ) { // We are loading an SSL page
  506.     if (substr($url, 0, strlen(HTTP_SERVER)) == HTTP_SERVER) { // NONSSL url
  507.       $url = HTTPS_SERVER . substr($url, strlen(HTTP_SERVER)); // Change it to SSL
  508.     }
  509.   }
  510.  
  511.   header('Location: ' . $url);
  512.  
  513.   tep_exit();
  514. }
  515.  
  516. to:
  517.  
  518. function tep_redirect($url) {
  519.   if ( (strstr($url, "\n") != false) || (strstr($url, "\r") != false) ) {
  520.     tep_redirect(tep_href_link(FILENAME_DEFAULT, '', 'NONSSL', false));
  521.   }
  522.  
  523.   if ( (ENABLE_SSL == true) && (getenv('HTTPS') == 'on') ) { // We are loading an SSL page
  524.     if (substr($url, 0, strlen(HTTP_SERVER)) == HTTP_SERVER) { // NONSSL url
  525.       $url = HTTPS_SERVER . substr($url, strlen(HTTP_SERVER)); // Change it to SSL
  526.     }
  527.   }
  528.  
  529.   header('Location: ' . $url);
  530.  
  531.   tep_exit();
  532. }
  533.  
  534. The following function must be replaced in catalog/admin/includes/functions/general.php.
  535.  
  536. Lines 15-26, from:
  537.  
  538. function tep_redirect($url) {
  539.   global $logger;
  540.  
  541.   header('Location: ' . $url);
  542.  
  543.   if (STORE_PAGE_PARSE_TIME == 'true') {
  544.     if (!is_object($logger)) $logger = new logger;
  545.     $logger->timer_stop();
  546.   }
  547.  
  548.   exit;
  549. }
  550.  
  551. to:
  552.  
  553. function tep_redirect($url) {
  554.   global $logger;
  555.  
  556.   if ( (strstr($url, "\n") != false) || (strstr($url, "\r") != false) ) {
  557.     tep_redirect(tep_href_link(FILENAME_DEFAULT, '', 'NONSSL', false));
  558.   }
  559.  
  560.   header('Location: ' . $url);
  561.  
  562.   if (STORE_PAGE_PARSE_TIME == 'true') {
  563.     if (!is_object($logger)) $logger = new logger;
  564.     $logger->timer_stop();
  565.   }
  566.  
  567.   exit;
  568. }
  569.  
  570. ------------------------------------------------------------------------------
  571. E-Mail Header Injection
  572. http://www.oscommerce.com/community/bugs,2488
  573. ------------------------------------------------------------------------------
  574.  
  575. Problem:
  576.  
  577. By using malicious data it is possible to inject headers into emails the online store sends. 
  578.  
  579. Solution:
  580.  
  581. The following function must be replaced in catalog/includes/classes/email.php and catalog/admin/includes/classes/email.php.
  582.  
  583. Lines 473-504, from:
  584.  
  585. function send($to_name, $to_addr, $from_name, $from_addr, $subject = '', $headers = '') {
  586.   $to = (($to_name != '') ? '"' . $to_name . '" <' . $to_addr . '>' : $to_addr);
  587.   $from = (($from_name != '') ? '"' . $from_name . '" <' . $from_addr . '>' : $from_addr);
  588.  
  589.   if (is_string($headers)) {
  590.     $headers = explode($this->lf, trim($headers));
  591.   }
  592.  
  593.   for ($i=0; $i<count($headers); $i++) {
  594.     if (is_array($headers[$i])) {
  595.       for ($j=0; $j<count($headers[$i]); $j++) {
  596.         if ($headers[$i][$j] != '') {
  597.           $xtra_headers[] = $headers[$i][$j];
  598.         }
  599.       }
  600.     }
  601.  
  602.     if ($headers[$i] != '') {
  603.       $xtra_headers[] = $headers[$i];
  604.     }
  605.   }
  606.  
  607.   if (!isset($xtra_headers)) {
  608.     $xtra_headers = array();
  609.   }
  610.  
  611.   if (EMAIL_TRANSPORT == 'smtp') {
  612.     return mail($to_addr, $subject, $this->output, 'From: ' . $from . $this->lf . 'To: ' . $to . $this->lf . implode($this->lf, $this->headers) . $this->lf . implode($this->lf, $xtra_headers));
  613.   } else {
  614.     return mail($to, $subject, $this->output, 'From: '.$from.$this->lf.implode($this->lf, $this->headers).$this->lf.implode($this->lf, $xtra_headers));
  615.   }
  616. }
  617.  
  618. to:
  619.  
  620. function send($to_name, $to_addr, $from_name, $from_addr, $subject = '', $headers = '') {
  621.   if ((strstr($to_name, "\n") != false) || (strstr($to_name, "\r") != false)) {
  622.     return false;
  623.   }
  624.  
  625.   if ((strstr($to_addr, "\n") != false) || (strstr($to_addr, "\r") != false)) {
  626.     return false;
  627.   }
  628.  
  629.   if ((strstr($subject, "\n") != false) || (strstr($subject, "\r") != false)) {
  630.     return false;
  631.   }
  632.  
  633.   if ((strstr($from_name, "\n") != false) || (strstr($from_name, "\r") != false)) {
  634.     return false;
  635.   }
  636.  
  637.   if ((strstr($from_addr, "\n") != false) || (strstr($from_addr, "\r") != false)) {
  638.     return false;
  639.   }
  640.  
  641.   $to = (($to_name != '') ? '"' . $to_name . '" <' . $to_addr . '>' : $to_addr);
  642.   $from = (($from_name != '') ? '"' . $from_name . '" <' . $from_addr . '>' : $from_addr);
  643.  
  644.   if (is_string($headers)) {
  645.     $headers = explode($this->lf, trim($headers));
  646.   }
  647.  
  648.   for ($i=0; $i<count($headers); $i++) {
  649.     if (is_array($headers[$i])) {
  650.       for ($j=0; $j<count($headers[$i]); $j++) {
  651.         if ($headers[$i][$j] != '') {
  652.           $xtra_headers[] = $headers[$i][$j];
  653.         }
  654.       }
  655.     }
  656.  
  657.     if ($headers[$i] != '') {
  658.       $xtra_headers[] = $headers[$i];
  659.     }
  660.   }
  661.  
  662.   if (!isset($xtra_headers)) {
  663.     $xtra_headers = array();
  664.   }
  665.  
  666.   if (EMAIL_TRANSPORT == 'smtp') {
  667.     return mail($to_addr, $subject, $this->output, 'From: ' . $from . $this->lf . 'To: ' . $to . $this->lf . implode($this->lf, $this->headers) . $this->lf . implode($this->lf, $xtra_headers));
  668.   } else {
  669.     return mail($to, $subject, $this->output, 'From: '.$from.$this->lf.implode($this->lf, $this->headers).$this->lf.implode($this->lf, $xtra_headers));
  670.   }
  671. }
  672.  
  673. ------------------------------------------------------------------------------
  674. Contact Us Form XSS Issue
  675. http://www.oscommerce.com/community/bugs,2422
  676. ------------------------------------------------------------------------------
  677.  
  678. Problem:
  679.  
  680. By using malicious data it is possible to inject HTML into the page. 
  681.  
  682. Solution:
  683.  
  684. Lines 221-225 in catalog/includes/functions/html_output.php must be changed from:
  685.  
  686. if ( (isset($GLOBALS[$name])) && ($reinsert_value == true) ) {
  687.   $field .= stripslashes($GLOBALS[$name]);
  688. } elseif (tep_not_null($text)) {
  689.   $field .= $text;
  690. }
  691.  
  692. to:
  693.  
  694. if ( (isset($GLOBALS[$name])) && ($reinsert_value == true) ) {
  695.   $field .= tep_output_string_protected(stripslashes($GLOBALS[$name]));
  696. } elseif (tep_not_null($text)) {
  697.   $field .= tep_output_string_protected($text);
  698. }
  699.  
  700. Lines 244-248 in catalog/admin/includes/functions/html_output.php must be changed from:
  701.  
  702. if ( (isset($GLOBALS[$name])) && ($reinsert_value == true) ) {
  703.   $field .= stripslashes($GLOBALS[$name]);
  704. } elseif (tep_not_null($text)) {
  705.   $field .= $text;
  706. }
  707.  
  708. to:
  709.  
  710. if ( (isset($GLOBALS[$name])) && ($reinsert_value == true) ) {
  711.   $field .= tep_output_string_protected(stripslashes($GLOBALS[$name]));
  712. } elseif (tep_not_null($text)) {
  713.   $field .= tep_output_string_protected($text);
  714. }
  715.  
  716. ------------------------------------------------------------------------------
  717. Open Redirector
  718. http://www.oscommerce.com/community/bugs,2970
  719. ------------------------------------------------------------------------------
  720.  
  721. Problem:
  722.  
  723. There is no URL checking being performed on the redirection page, and allows external sources to use the page as an open redirect relay.
  724.  
  725. Solution:
  726.  
  727. Lines 27-29 in catalog/redirect.php must be changed from:
  728.  
  729. if (isset($HTTP_GET_VARS['goto']) && tep_not_null($HTTP_GET_VARS['goto'])) {
  730.   tep_redirect('http://' . $HTTP_GET_VARS['goto']);
  731. }
  732.  
  733. to:
  734.  
  735. if (isset($HTTP_GET_VARS['goto']) && tep_not_null($HTTP_GET_VARS['goto'])) {
  736.   $check_query = tep_db_query("select products_url from " . TABLE_PRODUCTS_DESCRIPTION . " where products_url = '" . tep_db_input($HTTP_GET_VARS['goto']) . "' limit 1");
  737.   if (tep_db_num_rows($check_query)) {
  738.     tep_redirect('http://' . $HTTP_GET_VARS['goto']);
  739.   }
  740. }
  741.  
  742. ------------------------------------------------------------------------------
  743. Extra Slashes In New Products
  744. ------------------------------------------------------------------------------
  745.  
  746. Problem:
  747.  
  748. When new products are entered and previewed, hitting the back button to edit the product data again adds extra slashes to apostrophes in the products name and description.
  749.  
  750. Solution:
  751.  
  752. The following lines must be replaced in catalog/admin/categories.php:
  753.  
  754. Line 504, from:
  755.  
  756. <td class="main"><?php echo tep_image(DIR_WS_CATALOG_LANGUAGES . $languages[$i]['directory'] . '/images/' . $languages[$i]['image'], $languages[$i]['name']) . ' ' . tep_draw_input_field('products_name[' . $languages[$i]['id'] . ']', (isset($products_name[$languages[$i]['id']]) ? $products_name[$languages[$i]['id']] : tep_get_products_name($pInfo->products_id, $languages[$i]['id']))); ?></td>
  757.  
  758. to:
  759.  
  760. <td class="main"><?php echo tep_image(DIR_WS_CATALOG_LANGUAGES . $languages[$i]['directory'] . '/images/' . $languages[$i]['image'], $languages[$i]['name']) . ' ' . tep_draw_input_field('products_name[' . $languages[$i]['id'] . ']', (isset($products_name[$languages[$i]['id']]) ? stripslashes($products_name[$languages[$i]['id']]) : tep_get_products_name($pInfo->products_id, $languages[$i]['id']))); ?></td>
  761.  
  762. Line 538, from:
  763.  
  764. <td class="main"><?php echo tep_draw_textarea_field('products_description[' . $languages[$i]['id'] . ']', 'soft', '70', '15', (isset($products_description[$languages[$i]['id']]) ? $products_description[$languages[$i]['id']] : tep_get_products_description($pInfo->products_id, $languages[$i]['id']))); ?></td>
  765.  
  766. to:
  767.  
  768. <td class="main"><?php echo tep_draw_textarea_field('products_description[' . $languages[$i]['id'] . ']', 'soft', '70', '15', (isset($products_description[$languages[$i]['id']]) ? stripslashes($products_description[$languages[$i]['id']]) : tep_get_products_description($pInfo->products_id, $languages[$i]['id']))); ?></td>
  769.  
  770. Line 574, from:
  771.  
  772. <td class="main"><?php echo tep_image(DIR_WS_CATALOG_LANGUAGES . $languages[$i]['directory'] . '/images/' . $languages[$i]['image'], $languages[$i]['name']) . ' ' . tep_draw_input_field('products_url[' . $languages[$i]['id'] . ']', (isset($products_url[$languages[$i]['id']]) ? $products_url[$languages[$i]['id']] : tep_get_products_url($pInfo->products_id, $languages[$i]['id']))); ?></td>
  773.  
  774. to:
  775.  
  776. <td class="main"><?php echo tep_image(DIR_WS_CATALOG_LANGUAGES . $languages[$i]['directory'] . '/images/' . $languages[$i]['image'], $languages[$i]['name']) . ' ' . tep_draw_input_field('products_url[' . $languages[$i]['id'] . ']', (isset($products_url[$languages[$i]['id']]) ? stripslashes($products_url[$languages[$i]['id']]) : tep_get_products_url($pInfo->products_id, $languages[$i]['id']))); ?></td>
  777.  
  778. ------------------------------------------------------------------------------
  779. Order Status Filtering
  780. http://www.oscommerce.com/community/bugs,1543
  781. ------------------------------------------------------------------------------
  782.  
  783. Problem:
  784.  
  785. After changing the order status filtering on the Administration Tool -> Customers -> Orders page, selecting "All Orders" would show an empty listing of orders.
  786.  
  787. Solution:
  788.  
  789. Line 357 in catalog/admin/orders.php must be changed from:
  790.  
  791. } elseif (isset($HTTP_GET_VARS['status'])) {
  792.  
  793. to:
  794.  
  795. } elseif (isset($HTTP_GET_VARS['status']) && is_numeric($HTTP_GET_VARS['status']) && ($HTTP_GET_VARS['status'] > 0)) {
  796.  
  797. ------------------------------------------------------------------------------
  798. MySQL 5.0 Compatibility
  799. ------------------------------------------------------------------------------
  800.  
  801. Problem:
  802.  
  803. MySQL 5.0 introduces Server SQL modes as part of its SQL 2003 standards support, and uses a more stricter approach to executing SQL queries. This is performed by default with setting STRICT_TRANS_TABLES as a Server SQL mode.
  804.  
  805. Due to this new setting, MySQL fails on certain SQL queries and produces error messages on the screen.
  806.  
  807. Solution:
  808.  
  809. Lines 213-223 in catalog/advanced_search_result.php must be changed from:
  810.  
  811. $from_str = "from " . TABLE_PRODUCTS . " p left join " . TABLE_MANUFACTURERS . " m using(manufacturers_id) left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id, " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_CATEGORIES . " c, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c";
  812.  
  813. if ( (DISPLAY_PRICE_WITH_TAX == 'true') && (tep_not_null($pfrom) || tep_not_null($pto)) ) {
  814.   if (!tep_session_is_registered('customer_country_id')) {
  815.     $customer_country_id = STORE_COUNTRY;
  816.     $customer_zone_id = STORE_ZONE;
  817.   }
  818.   $from_str .= " left join " . TABLE_TAX_RATES . " tr on p.products_tax_class_id = tr.tax_class_id left join " . TABLE_ZONES_TO_GEO_ZONES . " gz on tr.tax_zone_id = gz.geo_zone_id and (gz.zone_country_id is null or gz.zone_country_id = '0' or gz.zone_country_id = '" . (int)$customer_country_id . "') and (gz.zone_id is null or gz.zone_id = '0' or gz.zone_id = '" . (int)$customer_zone_id . "')";
  819. }
  820.  
  821. $where_str = " where p.products_status = '1' and p.products_id = pd.products_id and pd.language_id = '" . (int)$languages_id . "' and p.products_id = p2c.products_id and p2c.categories_id = c.categories_id ";
  822.  
  823. to:
  824.  
  825. $from_str = "from " . TABLE_PRODUCTS . " p left join " . TABLE_MANUFACTURERS . " m using(manufacturers_id) left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id";
  826.  
  827. if ( (DISPLAY_PRICE_WITH_TAX == 'true') && (tep_not_null($pfrom) || tep_not_null($pto)) ) {
  828.   if (!tep_session_is_registered('customer_country_id')) {
  829.     $customer_country_id = STORE_COUNTRY;
  830.     $customer_zone_id = STORE_ZONE;
  831.   }
  832.   $from_str .= " left join " . TABLE_TAX_RATES . " tr on p.products_tax_class_id = tr.tax_class_id left join " . TABLE_ZONES_TO_GEO_ZONES . " gz on tr.tax_zone_id = gz.geo_zone_id and (gz.zone_country_id is null or gz.zone_country_id = '0' or gz.zone_country_id = '" . (int)$customer_country_id . "') and (gz.zone_id is null or gz.zone_id = '0' or gz.zone_id = '" . (int)$customer_zone_id . "')";
  833. }
  834.  
  835. $from_str .= ", " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_CATEGORIES . " c, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c";
  836.  
  837. $where_str = " where p.products_status = '1' and p.products_id = pd.products_id and pd.language_id = '" . (int)$languages_id . "' and p.products_id = p2c.products_id and p2c.categories_id = c.categories_id ";
  838.  
  839. The following lines must be replaced in catalog/index.php:
  840.  
  841. Line 175, from:
  842.  
  843. $listing_sql = "select " . $select_column_list . " p.products_id, p.manufacturers_id, p.products_price, p.products_tax_class_id, IF(s.status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_MANUFACTURERS . " m, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id where p.products_status = '1' and p.manufacturers_id = m.manufacturers_id and m.manufacturers_id = '" . (int)$HTTP_GET_VARS['manufacturers_id'] . "' and p.products_id = p2c.products_id and pd.products_id = p2c.products_id and pd.language_id = '" . (int)$languages_id . "' and p2c.categories_id = '" . (int)$HTTP_GET_VARS['filter_id'] . "'";
  844.  
  845. to:
  846.  
  847. $listing_sql = "select " . $select_column_list . " p.products_id, p.manufacturers_id, p.products_price, p.products_tax_class_id, IF(s.status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS . " p left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id, " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_MANUFACTURERS . " m, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c where p.products_status = '1' and p.manufacturers_id = m.manufacturers_id and m.manufacturers_id = '" . (int)$HTTP_GET_VARS['manufacturers_id'] . "' and p.products_id = p2c.products_id and pd.products_id = p2c.products_id and pd.language_id = '" . (int)$languages_id . "' and p2c.categories_id = '" . (int)$HTTP_GET_VARS['filter_id'] . "'";
  848.  
  849. Line 178, from:
  850.  
  851. $listing_sql = "select " . $select_column_list . " p.products_id, p.manufacturers_id, p.products_price, p.products_tax_class_id, IF(s.status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_MANUFACTURERS . " m left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id where p.products_status = '1' and pd.products_id = p.products_id and pd.language_id = '" . (int)$languages_id . "' and p.manufacturers_id = m.manufacturers_id and m.manufacturers_id = '" . (int)$HTTP_GET_VARS['manufacturers_id'] . "'";
  852.  
  853. to:
  854.  
  855. $listing_sql = "select " . $select_column_list . " p.products_id, p.manufacturers_id, p.products_price, p.products_tax_class_id, IF(s.status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS . " p left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id, " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_MANUFACTURERS . " m where p.products_status = '1' and pd.products_id = p.products_id and pd.language_id = '" . (int)$languages_id . "' and p.manufacturers_id = m.manufacturers_id and m.manufacturers_id = '" . (int)$HTTP_GET_VARS['manufacturers_id'] . "'";
  856.  
  857. Line 184, from:
  858.  
  859. $listing_sql = "select " . $select_column_list . " p.products_id, p.manufacturers_id, p.products_price, p.products_tax_class_id, IF(s.status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS . " p, " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_MANUFACTURERS . " m, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id where p.products_status = '1' and p.manufacturers_id = m.manufacturers_id and m.manufacturers_id = '" . (int)$HTTP_GET_VARS['filter_id'] . "' and p.products_id = p2c.products_id and pd.products_id = p2c.products_id and pd.language_id = '" . (int)$languages_id . "' and p2c.categories_id = '" . (int)$current_category_id . "'";
  860.  
  861. to:
  862.  
  863. $listing_sql = "select " . $select_column_list . " p.products_id, p.manufacturers_id, p.products_price, p.products_tax_class_id, IF(s.status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS . " p left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id, " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_MANUFACTURERS . " m, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c where p.products_status = '1' and p.manufacturers_id = m.manufacturers_id and m.manufacturers_id = '" . (int)$HTTP_GET_VARS['filter_id'] . "' and p.products_id = p2c.products_id and pd.products_id = p2c.products_id and pd.language_id = '" . (int)$languages_id . "' and p2c.categories_id = '" . (int)$current_category_id . "'";
  864.  
  865. Line 187, from:
  866.  
  867. $listing_sql = "select " . $select_column_list . " p.products_id, p.manufacturers_id, p.products_price, p.products_tax_class_id, IF(s.status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_PRODUCTS . " p left join " . TABLE_MANUFACTURERS . " m on p.manufacturers_id = m.manufacturers_id, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id where p.products_status = '1' and p.products_id = p2c.products_id and pd.products_id = p2c.products_id and pd.language_id = '" . (int)$languages_id . "' and p2c.categories_id = '" . (int)$current_category_id . "'";
  868.  
  869. to:
  870.  
  871. $listing_sql = "select " . $select_column_list . " p.products_id, p.manufacturers_id, p.products_price, p.products_tax_class_id, IF(s.status, s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status, s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_PRODUCTS . " p left join " . TABLE_MANUFACTURERS . " m on p.manufacturers_id = m.manufacturers_id left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c where p.products_status = '1' and p.products_id = p2c.products_id and pd.products_id = p2c.products_id and pd.language_id = '" . (int)$languages_id . "' and p2c.categories_id = '" . (int)$current_category_id . "'";
  872.  
  873. Line 292 in catalog/admin/categories.php must be changed from:
  874.  
  875. tep_db_query("insert into " . TABLE_PRODUCTS . " (products_quantity, products_model,products_image, products_price, products_date_added, products_date_available, products_weight, products_status, products_tax_class_id, manufacturers_id) values ('" . tep_db_input($product['products_quantity']) . "', '" . tep_db_input($product['products_model']) . "', '" . tep_db_input($product['products_image']) . "', '" . tep_db_input($product['products_price']) . "',  now(), '" . tep_db_input($product['products_date_available']) . "', '" . tep_db_input($product['products_weight']) . "', '0', '" . (int)$product['products_tax_class_id'] . "', '" . (int)$product['manufacturers_id'] . "')");
  876.  
  877. to:
  878.  
  879. tep_db_query("insert into " . TABLE_PRODUCTS . " (products_quantity, products_model,products_image, products_price, products_date_added, products_date_available, products_weight, products_status, products_tax_class_id, manufacturers_id) values ('" . tep_db_input($product['products_quantity']) . "', '" . tep_db_input($product['products_model']) . "', '" . tep_db_input($product['products_image']) . "', '" . tep_db_input($product['products_price']) . "',  now(), " . (empty($product['products_date_available']) ? "null" : "'" . tep_db_input($product['products_date_available']) . "'") . ", '" . tep_db_input($product['products_weight']) . "', '0', '" . (int)$product['products_tax_class_id'] . "', '" . (int)$product['manufacturers_id'] . "')");
  880.  
  881. The following SQL queries need to be performed:
  882.  
  883. ALTER TABLE whos_online MODIFY COLUMN last_page_url VARCHAR(255) NOT NULL;
  884.  
  885. ALTER TABLE customers MODIFY COLUMN customers_default_address_id INTEGER;
  886.  
  887. ALTER TABLE customers_basket MODIFY COLUMN final_price DECIMAL(15,4);
  888.