Quick Search:

View

Revision:

Diff

Diff from 711 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/osCommerce/oscommerce2/trunk/update-20060817.txt

Annotated File View

hpdl
711
1 osCommerce 2.2 Milestone 2 Update 060817
2 Update Package 17th August 2006
3
4 ------------------------------------------------------------------------------
5 Table of Contents
6 ------------------------------------------------------------------------------
7
8 ## Update 060817 (17th August 2006)
9
10 Magic Quotes Compatibility Layer Fix
11 Parse GET Variables In Cache Functions
12 PHP 3 Session ID XSS Issue
13 Product Attributes SQL Injection
14 Resize Images To Round Numbers
15
16 ## Update 051113 (13th November 2005)
17
18 customer_country_id in addressbook
19
20 ## Update 051112 (12th November 2005)
21
22 Cannot re-assign $this
23 limit -20, 20
24 Database Input Enhancement
25 Adding Non-Existing Products To Cart
26 Session ID XSS Issue
27 Validate Session ID
28 File Manager Problem
29 HTTP Header Injection
30 E-Mail Header Injection
31 Contact Us Form XSS Issue
32 Open Redirector
33 Extra Slashes In New Products
34 Order Status Filtering
35 MySQL 5.0 Compatibility
36
37 ###########################
38 ###### Update 060817 ######
39 ###########################
40
41 ------------------------------------------------------------------------------
42 Magic Quotes Compatibility Layer Fix
43 http://www.oscommerce.com/community/bugs,1435
44 http://svn.oscommerce.com/trac/changeset/706
45 ------------------------------------------------------------------------------
46
47 Problem:
48
49 The Magic Quotes compatibility layer does not parse arrays within the GET/POST/COOKIE scope that can be used to inject SQL into database queries.
50
51 Solution:
52
53 The following lines must be replaced in catalog/includes/functions/compatibility.php:
54
55 Lines 22-23, from:
56
57 if (is_array($value)) {
58   do_magic_quotes_gpc($value);
59
60 to:
61
62 if (is_array($ar[$key])) {
63   do_magic_quotes_gpc($ar[$key]);
64
65 The following lines must be replaced in catalog/admin/includes/functions/compatibility.php:
66
67 Lines 22-23, from:
68
69 if (is_array($value)) {
70   do_magic_quotes_gpc($value);
71
72 to:
73
74 if (is_array($ar[$key])) {
75   do_magic_quotes_gpc($ar[$key]);
76
77 ------------------------------------------------------------------------------
78 Parse GET Variables In Cache Functions
79 http://svn.oscommerce.com/trac/changeset/708
80 ------------------------------------------------------------------------------
81
82 Problem:
83
84 The GET variables used in caching functions are not parsed.
85
86 Solution:
87
88 The following lines must be replaced in catalog/includes/functions/cache.php:
89
90 Line 121, from:
91
92 if (isset($HTTP_GET_VARS['manufactuers_id']) && tep_not_null($HTTP_GET_VARS['manufacturers_id'])) {
93
94 to:
95
96 if (isset($HTTP_GET_VARS['manufactuers_id']) && is_numeric($HTTP_GET_VARS['manufacturers_id'])) {
97
98 Lines 142-148, from:
99
100 if (($refresh == true) || !read_cache($cache_output, 'also_purchased-' . $language . '.cache' . $HTTP_GET_VARS['products_id'], $auto_expire)) {
101   ob_start();
102   include(DIR_WS_MODULES . FILENAME_ALSO_PURCHASED_PRODUCTS);
103   $cache_output = ob_get_contents();
104   ob_end_clean();
105   write_cache($cache_output, 'also_purchased-' . $language . '.cache' . $HTTP_GET_VARS['products_id']);
106 }
107
108 to:
109
110 $cache_output = '';
111
112 if (isset($HTTP_GET_VARS['products_id']) && is_numeric($HTTP_GET_VARS['products_id'])) {
113   if (($refresh == true) || !read_cache($cache_output, 'also_purchased-' . $language . '.cache' . $HTTP_GET_VARS['products_id'], $auto_expire)) {
114     ob_start();
115     include(DIR_WS_MODULES . FILENAME_ALSO_PURCHASED_PRODUCTS);
116     $cache_output = ob_get_contents();
117     ob_end_clean();
118     write_cache($cache_output, 'also_purchased-' . $language . '.cache' . $HTTP_GET_VARS['products_id']);
119   }
120 }
121
122 ------------------------------------------------------------------------------
123 PHP 3 Session ID XSS Issue
124 http://svn.oscommerce.com/trac/changeset/709
125 ------------------------------------------------------------------------------
126
127 Problem:
128
129 The session ID in the PHP 3 compatibility layer is not being parsed.
130
131 Solution:
132
133 The following lines must be added in catalog/includes/classes/sessions.php:
134
135 Line 380:
136
137 if (!empty($session->id)) {
138   if (preg_match('/^[a-zA-Z0-9]+$/', $session->id) == false) {
139     unset($session->id);
140   }
141 }
142
143 ------------------------------------------------------------------------------
144 Product Attributes SQL Injection
145 http://svn.oscommerce.com/trac/changeset/703
146 ------------------------------------------------------------------------------
147
148 Problem:
149
150 With the failure of arrays not being parsed by the magic_quotes_gpc compatibility layer, it is possible to inject SQL into database queries.
151
152 Solution:
153
154 The following lines must be replaced in catalog/includes/classes/shopping_cart.php:
155
156 Line 84, from:
157
158 if (is_numeric($products_id) && is_numeric($qty)) {
159
160 to:
161
162 $attributes_pass_check = true;
163
164 if (is_array($attributes)) {
165   reset($attributes);
166   while (list($option, $value) = each($attributes)) {
167     if (!is_numeric($option) || !is_numeric($value)) {
168       $attributes_pass_check = false;
169       break;
170     }
171   }
172 }
173
174 if (is_numeric($products_id) && is_numeric($qty) && ($attributes_pass_check == true)) {
175
176 Line 125, from:
177
178 if (is_numeric($products_id) && isset($this->contents[$products_id_string]) && is_numeric($quantity)) {
179
180 to:
181
182 $attributes_pass_check = true;
183
184 if (is_array($attributes)) {
185   reset($attributes);
186   while (list($option, $value) = each($attributes)) {
187     if (!is_numeric($option) || !is_numeric($value)) {
188       $attributes_pass_check = false;
189       break;
190     }
191   }
192 }
193
194 if (is_numeric($products_id) && isset($this->contents[$products_id_string]) && is_numeric($quantity) && ($attributes_pass_check == true)) {
195
196 The following lines must be replaced in catalog/shopping_cart.php:
197
198 Lines 84-85, from:
199
200 where pa.products_id = '" . $products[$i]['id'] . "'
201 and pa.options_id = '" . $option . "'
202
203 to:
204
205 where pa.products_id = '" . (int)$products[$i]['id'] . "'
206 and pa.options_id = '" . (int)$option . "'
207
208 Line 87, from:
209
210 and pa.options_values_id = '" . $value . "'
211
212 to:
213
214 and pa.options_values_id = '" . (int)$value . "'
215
216 Lines 89-90, from:
217
218 and popt.language_id = '" . $languages_id . "'
219 and poval.language_id = '" . $languages_id . "'");
220
221 to:
222
223 and popt.language_id = '" . (int)$languages_id . "'
224 and poval.language_id = '" . (int)$languages_id . "'");
225
226 ------------------------------------------------------------------------------
227 Resize Images To Round Numbers
228 http://www.oscommerce.com/community/bugs,1371
229 http://svn.oscommerce.com/trac/changeset/707
230 ------------------------------------------------------------------------------
231
232 Problem:
233
234 The image resizing logic may result in decimal numbers which the HTML specification does not allow.
235
236 Solution:
237
238 The following lines must be replaced in catalog/includes/functions/html_output.php:
239
240 Line 91, from:
241
242 $width = $image_size[0] * $ratio;
243
244 to:
245
246 $width = intval($image_size[0] * $ratio);
247
248 Line 94, from:
249
250 $height = $image_size[1] * $ratio;
251
252 to:
253
254 $height = intval($image_size[1] * $ratio);
255
256 ###########################
257 ###### Update 051113 ######
258 ###########################
259
260 ------------------------------------------------------------------------------
261 customer_country_id in addressbook
262 http://www.oscommerce.com/community/bugs,1662
263 ------------------------------------------------------------------------------
264
265 Problem:
266
267 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.
268
269 Solution:
270
271 The following lines must be replaced in catalog/address_book_process.php:
272
273 Line 150, from:
274
275 $customer_country_id = $country_id;
276
277 to:
278
279 $customer_country_id = $country;
280
281 Line 171, from:
282
283 $customer_country_id = $country_id;
284
285 to:
286
287 $customer_country_id = $country;
288
289 ###########################
290 ###### Update 051112 ######
291 ###########################
292
293 ------------------------------------------------------------------------------
294 Cannot re-assign $this
295 http://www.oscommerce.com/community/bugs,1650
296 ------------------------------------------------------------------------------
297
298 Problem:
299
300 Fatal error: Cannot re-assign $this in /path/to/catalog/admin/includes/classes/upload.php on line 31
301
302 Solution:
303
304 Lines 27-34 in catalog/admin/includes/classes/upload.php must be changed from:
305
306 if ( ($this->parse() == true) && ($this->save() == true) ) {
307   return true;
308 } else {
309 // self destruct
310   $this = null;
311
312   return false;
313 }
314
315 to:
316
317 if ( ($this->parse() == true) && ($this->save() == true) ) {
318   return true;
319 } else {
320   return false;
321 }
322
323 ------------------------------------------------------------------------------
324 limit -20, 20
325 http://www.oscommerce.com/community/bugs,1605
326 ------------------------------------------------------------------------------
327
328 Problem:
329
330 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
331
332 Solution:
333
334 Line 67 in catalog/includes/classes/split_page_results.php must be changed from:
335
336 $this->sql_query .= " limit " . $offset . ", " . $this->number_of_rows_per_page;
337
338 to:
339
340 $this->sql_query .= " limit " . max($offset, 0) . ", " . $this->number_of_rows_per_page;
341
342 Line 38 in catalog/admin/includes/classes/split_page_results.php must be changed from:
343
344 $sql_query .= " limit " . $offset . ", " . $max_rows_per_page;
345
346 to:
347
348 $sql_query .= " limit " . max($offset, 0) . ", " . $max_rows_per_page;
349
350 ------------------------------------------------------------------------------
351 Database Input Enhancement
352 ------------------------------------------------------------------------------
353
354 Problem:
355
356 Native MySQL functions should be used in preference to the addslashes() function, to properly protect the SQL queries being executed on the database server.
357
358 Solution:
359
360 The following function must be replaced in catalog/includes/functions/database.php.
361
362 Lines 126-128, from:
363
364 function tep_db_input($string) {
365   return addslashes($string);
366 }
367
368 to:
369
370 function tep_db_input($string, $link = 'db_link') {
371   global $$link;
372
373   if (function_exists('mysql_real_escape_string')) {
374     return mysql_real_escape_string($string, $$link);
375   } elseif (function_exists('mysql_escape_string')) {
376     return mysql_escape_string($string);
377   }
378
379   return addslashes($string);
380 }
381
382 The following function must be replaced in catalog/admin/includes/functions/database.php.
383
384 Lines 130-132, from:
385
386 function tep_db_input($string) {
387   return addslashes($string);
388 }
389
390 to:
391
392 function tep_db_input($string, $link = 'db_link') {
393   global $$link;
394
395   if (function_exists('mysql_real_escape_string')) {
396     return mysql_real_escape_string($string, $$link);
397   } elseif (function_exists('mysql_escape_string')) {
398     return mysql_escape_string($string);
399   }
400
401   return addslashes($string);
402 }
403
404 ------------------------------------------------------------------------------
405 Adding Non-Existing Products To Cart
406 http://www.oscommerce.com/community/bugs,1617
407 ------------------------------------------------------------------------------
408
409 Problem:
410
411 It is possible to add non-existing products into the shopping cart which may prevent customers from removing the products from their cart.
412
413 Solution:
414
415 The following functions must be replaced in catalog/includes/functions/general.php.
416
417 Lines 912-921, from:
418
419 function tep_get_uprid($prid, $params) {
420   $uprid = $prid;
421   if ( (is_array($params)) && (!strstr($prid, '{')) ) {
422     while (list($option, $value) = each($params)) {
423       $uprid = $uprid . '{' . $option . '}' . $value;
424     }
425   }
426
427   return $uprid;
428 }
429
430 to:
431
432 function tep_get_uprid($prid, $params) {
433   if (is_numeric($prid)) {
434     $uprid = $prid;
435
436     if (is_array($params) && (sizeof($params) > 0)) {
437       $attributes_check = true;
438       $attributes_ids = '';
439
440       reset($params);
441       while (list($option, $value) = each($params)) {
442         if (is_numeric($option) && is_numeric($value)) {
443           $attributes_ids .= '{' . (int)$option . '}' . (int)$value;
444         } else {
445           $attributes_check = false;
446           break;
447         }
448       }
449
450       if ($attributes_check == true) {
451         $uprid .= $attributes_ids;
452       }
453     }
454   } else {
455     $uprid = tep_get_prid($prid);
456
457     if (is_numeric($uprid)) {
458       if (strpos($prid, '{') !== false) {
459         $attributes_check = true;
460         $attributes_ids = '';
461
462 // strpos()+1 to remove up to and including the first { which would create an empty array element in explode()
463         $attributes = explode('{', substr($prid, strpos($prid, '{')+1));
464
465         for ($i=0, $n=sizeof($attributes); $i<$n; $i++) {
466           $pair = explode('}', $attributes[$i]);
467
468           if (is_numeric($pair[0]) && is_numeric($pair[1])) {
469             $attributes_ids .= '{' . (int)$pair[0] . '}' . (int)$pair[1];
470           } else {
471             $attributes_check = false;
472             break;
473           }
474         }
475
476         if ($attributes_check == true) {
477           $uprid .= $attributes_ids;
478         }
479       }
480     } else {
481       return false;
482     }
483   }
484
485   return $uprid;
486 }
487
488 Lines 925-929, from:
489
490 function tep_get_prid($uprid) {
491   $pieces = explode('{', $uprid);
492
493   return $pieces[0];
494 }
495
496 to:
497
498 function tep_get_prid($uprid) {
499   $pieces = explode('{', $uprid);
500
501   if (is_numeric($pieces[0])) {
502     return $pieces[0];
503   } else {
504     return false;
505   }
506 }
507
508 The following functions must be replaced in catalog/includes/classes/shopping_cart.php.
509
510 Lines 78-108, from:
511
512 function add_cart($products_id, $qty = '1', $attributes = '', $notify = true) {
513   global $new_products_id_in_cart, $customer_id;
514
515   $products_id = tep_get_uprid($products_id, $attributes);
516   if ($notify == true) {
517     $new_products_id_in_cart = $products_id;
518     tep_session_register('new_products_id_in_cart');
519   }
520
521   if ($this->in_cart($products_id)) {
522     $this->update_quantity($products_id, $qty, $attributes);
523   } else {
524     $this->contents[] = array($products_id);
525     $this->contents[$products_id] = array('qty' => $qty);
526 // insert into database
527     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') . "')");
528
529     if (is_array($attributes)) {
530       reset($attributes);
531       while (list($option, $value) = each($attributes)) {
532         $this->contents[$products_id]['attributes'][$option] = $value;
533 // insert into database
534         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 . "')");
535       }
536     }
537   }
538   $this->cleanup();
539
540 // assign a temporary unique ID to the order contents to prevent hack attempts during the checkout procedure
541   $this->cartID = $this->generate_cart_id();
542 }
543
544 to:
545
546 function add_cart($products_id, $qty = '1', $attributes = '', $notify = true) {
547   global $new_products_id_in_cart, $customer_id;
548
549   $products_id_string = tep_get_uprid($products_id, $attributes);
550   $products_id = tep_get_prid($products_id_string);
551
552   if (is_numeric($products_id) && is_numeric($qty)) {
553     $check_product_query = tep_db_query("select products_status from " . TABLE_PRODUCTS . " where products_id = '" . (int)$products_id . "'");
554     $check_product = tep_db_fetch_array($check_product_query);
555
556     if (($check_product !== false) && ($check_product['products_status'] == '1')) {
557       if ($notify == true) {
558         $new_products_id_in_cart = $products_id;
559         tep_session_register('new_products_id_in_cart');
560       }
561
562       if ($this->in_cart($products_id_string)) {
563         $this->update_quantity($products_id_string, $qty, $attributes);
564       } else {
565         $this->contents[$products_id_string] = array('qty' => $qty);
566 // insert into database
567         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') . "')");
568
569         if (is_array($attributes)) {
570           reset($attributes);
571           while (list($option, $value) = each($attributes)) {
572             $this->contents[$products_id_string]['attributes'][$option] = $value;
573 // insert into database
574             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 . "')");
575           }
576         }
577       }
578
579       $this->cleanup();
580
581 // assign a temporary unique ID to the order contents to prevent hack attempts during the checkout procedure
582       $this->cartID = $this->generate_cart_id();
583     }
584   }
585 }
586
587 Lines 110-127, from:
588
589 function update_quantity($products_id, $quantity = '', $attributes = '') {
590   global $customer_id;
591
592   if (empty($quantity)) return true; // nothing needs to be updated if theres no quantity, so we return true..
593
594   $this->contents[$products_id] = array('qty' => $quantity);
595 // update database
596   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) . "'");
597
598   if (is_array($attributes)) {
599     reset($attributes);
600     while (list($option, $value) = each($attributes)) {
601       $this->contents[$products_id]['attributes'][$option] = $value;
602 // update database
603       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 . "'");
604     }
605   }
606 }
607
608 to:
609
610 function update_quantity($products_id, $quantity = '', $attributes = '') {
611   global $customer_id;
612
613   $products_id_string = tep_get_uprid($products_id, $attributes);
614   $products_id = tep_get_prid($products_id_string);
615
616   if (is_numeric($products_id) && isset($this->contents[$products_id_string]) && is_numeric($quantity)) {
617     $this->contents[$products_id_string] = array('qty' => $quantity);
618 // update database
619     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) . "'");
620
621     if (is_array($attributes)) {
622       reset($attributes);
623       while (list($option, $value) = each($attributes)) {
624         $this->contents[$products_id_string]['attributes'][$option] = $value;
625 // update database
626         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 . "'");
627       }
628     }
629   }
630 }
631
632 ------------------------------------------------------------------------------
633 Session ID XSS Issue
634 http://www.oscommerce.com/community/bugs,1546
635 ------------------------------------------------------------------------------
636
637 Problem:
638
639 A cross site scripting issue exists with malformed session IDs being used in the tep_href_link() function.
640
641 Solution:
642
643 Line 66 in catalog/includes/functions/html_output.php must be changed from:
644
645 $link .= $separator . $_sid;
646
647 to:
648
649 $link .= $separator . tep_output_string($_sid);
650
651 ------------------------------------------------------------------------------
652 Validate Session ID
653 ------------------------------------------------------------------------------
654
655 Problem:
656
657 Validate the session ID and redirect to the front page when an invalid session ID is requested.
658
659 Solution:
660
661 The following function must be replaced in catalog/includes/functions/sessions.php.
662
663 Lines 66-68, from:
664
665 function tep_session_start() {
666   return session_start();
667 }
668
669 to:
670
671 function tep_session_start() {
672   global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS;
673
674   $sane_session_id = true;
675
676   if (isset($HTTP_GET_VARS[tep_session_name()])) {
677     if (preg_match('/^[a-zA-Z0-9]+$/', $HTTP_GET_VARS[tep_session_name()]) == false) {
678       unset($HTTP_GET_VARS[tep_session_name()]);
679
680       $sane_session_id = false;
681     }
682   } elseif (isset($HTTP_POST_VARS[tep_session_name()])) {
683     if (preg_match('/^[a-zA-Z0-9]+$/', $HTTP_POST_VARS[tep_session_name()]) == false) {
684       unset($HTTP_POST_VARS[tep_session_name()]);
685
686       $sane_session_id = false;
687     }
688   } elseif (isset($HTTP_COOKIE_VARS[tep_session_name()])) {
689     if (preg_match('/^[a-zA-Z0-9]+$/', $HTTP_COOKIE_VARS[tep_session_name()]) == false) {
690       $session_data = session_get_cookie_params();
691
692       setcookie(tep_session_name(), '', time()-42000, $session_data['path'], $session_data['domain']);
693
694       $sane_session_id = false;
695     }
696   }
697
698   if ($sane_session_id == false) {
699     tep_redirect(tep_href_link(FILENAME_DEFAULT, '', 'NONSSL', false));
700   }
701
702   return session_start();
703 }
704
705 ------------------------------------------------------------------------------
706 File Manager Problem
707 http://www.oscommerce.com/community/bugs,1391
708 ------------------------------------------------------------------------------
709
710 Problem:
711
712 Parsing errors occur when saving edited files through the File Manager.
713
714 Solution:
715
716 Line 148 in catalog/admin/file_manager.php must be changed from:
717
718 $file_contents = htmlspecialchars(implode('', $file_array));
719
720 to:
721
722 $file_contents = addslashes(implode('', $file_array));
723
724 Note: This update also requires the Contact Us Form XSS Issue update in order to function correctly.
725
726 ------------------------------------------------------------------------------
727 HTTP Header Injection
728 ------------------------------------------------------------------------------
729
730 Problem:
731
732 By using malicious data it is possible to inject headers into HTTP requests. 
733 Solution:
734
735 The following function must be replaced in catalog/includes/functions/general.php.
736
737 Lines 22-32, from:
738
739 function tep_redirect($url) {
740   if ( (ENABLE_SSL == true) && (getenv('HTTPS') == 'on') ) { // We are loading an SSL page
741     if (substr($url, 0, strlen(HTTP_SERVER)) == HTTP_SERVER) { // NONSSL url
742       $url = HTTPS_SERVER . substr($url, strlen(HTTP_SERVER)); // Change it to SSL
743     }
744   }
745
746   header('Location: ' . $url);
747
748   tep_exit();
749 }
750
751 to:
752
753 function tep_redirect($url) {
754   if ( (strstr($url, "\n") != false) || (strstr($url, "\r") != false) ) {
755     tep_redirect(tep_href_link(FILENAME_DEFAULT, '', 'NONSSL', false));
756   }
757
758   if ( (ENABLE_SSL == true) && (getenv('HTTPS') == 'on') ) { // We are loading an SSL page
759     if (substr($url, 0, strlen(HTTP_SERVER)) == HTTP_SERVER) { // NONSSL url
760       $url = HTTPS_SERVER . substr($url, strlen(HTTP_SERVER)); // Change it to SSL
761     }
762   }
763
764   header('Location: ' . $url);
765
766   tep_exit();
767 }
768
769 The following function must be replaced in catalog/admin/includes/functions/general.php.
770
771 Lines 15-26, from:
772
773 function tep_redirect($url) {
774   global $logger;
775
776   header('Location: ' . $url);
777
778   if (STORE_PAGE_PARSE_TIME == 'true') {
779     if (!is_object($logger)) $logger = new logger;
780     $logger->timer_stop();
781   }
782
783   exit;
784 }
785
786 to:
787
788 function tep_redirect($url) {
789   global $logger;
790
791   if ( (strstr($url, "\n") != false) || (strstr($url, "\r") != false) ) {
792     tep_redirect(tep_href_link(FILENAME_DEFAULT, '', 'NONSSL', false));
793   }
794
795   header('Location: ' . $url);
796
797   if (STORE_PAGE_PARSE_TIME == 'true') {
798     if (!is_object($logger)) $logger = new logger;
799     $logger->timer_stop();
800   }
801
802   exit;
803 }
804
805 ------------------------------------------------------------------------------
806 E-Mail Header Injection
807 http://www.oscommerce.com/community/bugs,2488
808 ------------------------------------------------------------------------------
809
810 Problem:
811
812 By using malicious data it is possible to inject headers into emails the online store sends. 
813
814 Solution:
815
816 The following function must be replaced in catalog/includes/classes/email.php and catalog/admin/includes/classes/email.php.
817
818 Lines 473-504, from:
819
820 function send($to_name, $to_addr, $from_name, $from_addr, $subject = '', $headers = '') {
821   $to = (($to_name != '') ? '"' . $to_name . '" <' . $to_addr . '>' : $to_addr);
822   $from = (($from_name != '') ? '"' . $from_name . '" <' . $from_addr . '>' : $from_addr);
823
824   if (is_string($headers)) {
825     $headers = explode($this->lf, trim($headers));
826   }
827
828   for ($i=0; $i<count($headers); $i++) {
829     if (is_array($headers[$i])) {
830       for ($j=0; $j<count($headers[$i]); $j++) {
831         if ($headers[$i][$j] != '') {
832           $xtra_headers[] = $headers[$i][$j];
833         }
834       }
835     }
836
837     if ($headers[$i] != '') {
838       $xtra_headers[] = $headers[$i];
839     }
840   }
841
842   if (!isset($xtra_headers)) {
843     $xtra_headers = array();
844   }
845
846   if (EMAIL_TRANSPORT == 'smtp') {
847     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));
848   } else {
849     return mail($to, $subject, $this->output, 'From: '.$from.$this->lf.implode($this->lf, $this->headers).$this->lf.implode($this->lf, $xtra_headers));
850   }
851 }
852
853 to:
854
855 function send($to_name, $to_addr, $from_name, $from_addr, $subject = '', $headers = '') {
856   if ((strstr($to_name, "\n") != false) || (strstr($to_name, "\r") != false)) {
857     return false;
858   }
859
860   if ((strstr($to_addr, "\n") != false) || (strstr($to_addr, "\r") != false)) {
861     return false;
862   }
863
864   if ((strstr($subject, "\n") != false) || (strstr($subject, "\r") != false)) {
865     return false;
866   }
867
868   if ((strstr($from_name, "\n") != false) || (strstr($from_name, "\r") != false)) {
869     return false;
870   }
871
872   if ((strstr($from_addr, "\n") != false) || (strstr($from_addr, "\r") != false)) {
873     return false;
874   }
875
876   $to = (($to_name != '') ? '"' . $to_name . '" <' . $to_addr . '>' : $to_addr);
877   $from = (($from_name != '') ? '"' . $from_name . '" <' . $from_addr . '>' : $from_addr);
878
879   if (is_string($headers)) {
880     $headers = explode($this->lf, trim($headers));
881   }
882
883   for ($i=0; $i<count($headers); $i++) {
884     if (is_array($headers[$i])) {
885       for ($j=0; $j<count($headers[$i]); $j++) {
886         if ($headers[$i][$j] != '') {
887           $xtra_headers[] = $headers[$i][$j];
888         }
889       }
890     }
891
892     if ($headers[$i] != '') {
893       $xtra_headers[] = $headers[$i];
894     }
895   }
896
897   if (!isset($xtra_headers)) {
898     $xtra_headers = array();
899   }
900
901   if (EMAIL_TRANSPORT == 'smtp') {
902     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));
903   } else {
904     return mail($to, $subject, $this->output, 'From: '.$from.$this->lf.implode($this->lf, $this->headers).$this->lf.implode($this->lf, $xtra_headers));
905   }
906 }
907
908 ------------------------------------------------------------------------------
909 Contact Us Form XSS Issue
910 http://www.oscommerce.com/community/bugs,2422
911 ------------------------------------------------------------------------------
912
913 Problem:
914
915 By using malicious data it is possible to inject HTML into the page. 
916
917 Solution:
918
919 Lines 221-225 in catalog/includes/functions/html_output.php must be changed from:
920
921 if ( (isset($GLOBALS[$name])) && ($reinsert_value == true) ) {
922   $field .= stripslashes($GLOBALS[$name]);
923 } elseif (tep_not_null($text)) {
924   $field .= $text;
925 }
926
927 to:
928
929 if ( (isset($GLOBALS[$name])) && ($reinsert_value == true) ) {
930   $field .= tep_output_string_protected(stripslashes($GLOBALS[$name]));
931 } elseif (tep_not_null($text)) {
932   $field .= tep_output_string_protected($text);
933 }
934
935 Lines 244-248 in catalog/admin/includes/functions/html_output.php must be changed from:
936
937 if ( (isset($GLOBALS[$name])) && ($reinsert_value == true) ) {
938   $field .= stripslashes($GLOBALS[$name]);
939 } elseif (tep_not_null($text)) {
940   $field .= $text;
941 }
942
943 to:
944
945 if ( (isset($GLOBALS[$name])) && ($reinsert_value == true) ) {
946   $field .= tep_output_string_protected(stripslashes($GLOBALS[$name]));
947 } elseif (tep_not_null($text)) {
948   $field .= tep_output_string_protected($text);
949 }
950
951 ------------------------------------------------------------------------------
952 Open Redirector
953 http://www.oscommerce.com/community/bugs,2970
954 ------------------------------------------------------------------------------
955
956 Problem:
957
958 There is no URL checking being performed on the redirection page, and allows external sources to use the page as an open redirect relay.
959
960 Solution:
961
962 Lines 27-29 in catalog/redirect.php must be changed from:
963
964 if (isset($HTTP_GET_VARS['goto']) && tep_not_null($HTTP_GET_VARS['goto'])) {
965   tep_redirect('http://' . $HTTP_GET_VARS['goto']);
966 }
967
968 to:
969
970 if (isset($HTTP_GET_VARS['goto']) && tep_not_null($HTTP_GET_VARS['goto'])) {
971   $check_query = tep_db_query("select products_url from " . TABLE_PRODUCTS_DESCRIPTION . " where products_url = '" . tep_db_input($HTTP_GET_VARS['goto']) . "' limit 1");
972   if (tep_db_num_rows($check_query)) {
973     tep_redirect('http://' . $HTTP_GET_VARS['goto']);
974   }
975 }
976
977 ------------------------------------------------------------------------------
978 Extra Slashes In New Products
979 ------------------------------------------------------------------------------
980
981 Problem:
982
983 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.
984
985 Solution:
986
987 The following lines must be replaced in catalog/admin/categories.php:
988
989 Line 504, from:
990
991 <td class="main"><?php echo tep_image(DIR_WS_CATALOG_LANGUAGES . $languages[$i]['directory'] . '/images/' . $languages[$i]['image'], $languages[$i]['name']) . '&nbsp;' . 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>
992
993 to:
994
995 <td class="main"><?php echo tep_image(DIR_WS_CATALOG_LANGUAGES . $languages[$i]['directory'] . '/images/' . $languages[$i]['image'], $languages[$i]['name']) . '&nbsp;' . 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>
996
997 Line 538, from:
998
999 <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>
1000
1001 to:
1002
1003 <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>
1004
1005 Line 574, from:
1006
1007 <td class="main"><?php echo tep_image(DIR_WS_CATALOG_LANGUAGES . $languages[$i]['directory'] . '/images/' . $languages[$i]['image'], $languages[$i]['name']) . '&nbsp;' . 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>
1008
1009 to:
1010
1011 <td class="main"><?php echo tep_image(DIR_WS_CATALOG_LANGUAGES . $languages[$i]['directory'] . '/images/' . $languages[$i]['image'], $languages[$i]['name']) . '&nbsp;' . 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>
1012
1013 ------------------------------------------------------------------------------
1014 Order Status Filtering
1015 http://www.oscommerce.com/community/bugs,1543
1016 ------------------------------------------------------------------------------
1017
1018 Problem:
1019
1020 After changing the order status filtering on the Administration Tool -> Customers -> Orders page, selecting "All Orders" would show an empty listing of orders.
1021
1022 Solution:
1023
1024 Line 357 in catalog/admin/orders.php must be changed from:
1025
1026 } elseif (isset($HTTP_GET_VARS['status'])) {
1027
1028 to:
1029
1030 } elseif (isset($HTTP_GET_VARS['status']) && is_numeric($HTTP_GET_VARS['status']) && ($HTTP_GET_VARS['status'] > 0)) {
1031
1032 ------------------------------------------------------------------------------
1033 MySQL 5.0 Compatibility
1034 ------------------------------------------------------------------------------
1035
1036 Problem:
1037
1038 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.
1039
1040 Due to this new setting, MySQL fails on certain SQL queries and produces error messages on the screen.
1041
1042 Solution:
1043
1044 Lines 213-223 in catalog/advanced_search_result.php must be changed from:
1045
1046 $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";
1047
1048 if ( (DISPLAY_PRICE_WITH_TAX == 'true') && (tep_not_null($pfrom) || tep_not_null($pto)) ) {
1049   if (!tep_session_is_registered('customer_country_id')) {
1050     $customer_country_id = STORE_COUNTRY;
1051     $customer_zone_id = STORE_ZONE;
1052   }
1053   $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 . "')";
1054 }
1055
1056 $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 ";
1057
1058 to:
1059
1060 $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";
1061
1062 if ( (DISPLAY_PRICE_WITH_TAX == 'true') && (tep_not_null($pfrom) || tep_not_null($pto)) ) {
1063   if (!tep_session_is_registered('customer_country_id')) {
1064     $customer_country_id = STORE_COUNTRY;
1065     $customer_zone_id = STORE_ZONE;
1066   }
1067   $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 . "')";
1068 }
1069
1070 $from_str .= ", " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_CATEGORIES . " c, " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c";
1071
1072 $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 ";
1073
1074 The following lines must be replaced in catalog/index.php:
1075
1076 Line 175, from:
1077
1078 $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'] . "'";
1079
1080 to:
1081
1082 $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'] . "'";
1083
1084 Line 178, from:
1085
1086 $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'] . "'";
1087
1088 to:
1089
1090 $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'] . "'";
1091
1092 Line 184, from:
1093
1094 $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 . "'";
1095
1096 to:
1097
1098 $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 . "'";
1099
1100 Line 187, from:
1101
1102 $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 . "'";
1103
1104 to:
1105
1106 $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 . "'";
1107
1108 Line 292 in catalog/admin/categories.php must be changed from:
1109
1110 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'] . "')");
1111
1112 to:
1113
1114 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'] . "')");
1115
1116 The following SQL queries need to be performed:
1117
1118 ALTER TABLE whos_online MODIFY COLUMN last_page_url VARCHAR(255) NOT NULL;
1119
1120 ALTER TABLE customers MODIFY COLUMN customers_default_address_id INTEGER;
1121
1122 ALTER TABLE customers_basket MODIFY COLUMN final_price DECIMAL(15,4);