The document discusses various optimizations that can be made to improve the performance and security of a PrestaShop installation. It covers optimizations to server infrastructure, database queries, PHP code, and front-end performance. Key recommendations include using caching, minimizing database queries and regular expressions, compressing responses, and securing against common attacks like SQL injection. Measurements are suggested to identify bottlenecks before optimizing.
10. Your architecture has to be efficient (good planning) You have to code using best practices (don't do **obviously** stupid things) But prefer rather maintability and readibility of code over the speed When speed is not critical (i.e. real time systems, high traffic sites), you can improve it in later iterations When to optimize?
11. Measure first! You should know bottlenecks. Benchmark different scenarios and configs Going Linux? Test Linux, not Win. There are differences Will have 10000 products in your store? Test your modules with db of 10000, not 5 Is a 1% improvement worth of additional work? What about 5%? 10%? Try to estimate coding cost vs. hardware cost Sometimes it's just cheaper to add RAM What to optimize?
12. Small performance gains Using (int) instead of intval() can be even 4 X faster But overall gain is negligable (unless you are Facebook) Code executed once Tools::setCookieLanguage could be improved, but it is executed once Mythical optimisations ( ” vs ' ) But ”$a $b $c” … is faster than $a.” ”.$b.” ”.$c Whatshouldn'tbeoptimised
13. Server load: ab, siege, multi-mechanize ... Databaseload: MySql Slow Query Log, mysql proxy, ... EXPLAIN PHP: xdebug, dbg, xhprof ... Network / client side Yslow, firebug, WebKitinspector, dynaTrace AJAX, fiddler, google webmaster tools How to measure?
14. Server: Difficult task, often impossible on shared hostings Ask your admin CPU is rarely a bottleneck, generally indicates problems with suboptimal code RAM is cheap but not unlimited – attention to memory consuming scripts Typical problem: gd + jpg -> 2 Mb on disk, 33 Mb decompressed into memory Ramdisk for often accessed, not critical files (frameworks, configuration, tmp) Most common bottleneck: I/O (filesystem, dbs) Improving infrastructure
15. Every call to fs costs, depending the OS, filesystem and number of files Always use absolute paths in require / include Performance may start to degrade if you have more than 50 000 files in a directory Each product has image, each image has 6 thumbnails Debian + Apache 1.3 (shared hosting, nfs): Filesystem # Files Glob('*') exec. in sec. file_exists / sec. 1000 4,59 36000 11000 13,30 21000 65000 55,81 1475 122000 142,16 718
16. Directory content splitting: img/p/534-189-small.jpg becomes img/p/small/534-189.jpg Reading transparently via .htaccess RewriteRule (.*)/p/([^/]*)homejpg $1/p/home/$2home.jpg Writingtransparently via class if (!imageResize($file, $dir.$imageType['name'].'/'.$language['iso_code'].'-default- '.stripslashes($imageType['name']).'.jpg', ... Solution
17.
18. Avoid to using too many JOINSSELECT * FROM ps_feature` f LEFT JOIN ps_feature_lang` fl ON ( f.`id_feature` = fl.`id_feature` AND fl.`id_lang` = 1) WHERE f.`id_feature` = 1SELECT * FROM ps_feature_lang` fl WHER fl.`id_feature` = 1 AND fl.`id_lang` = 1 Version Tables Columns Without index 1.1.0.5 88 458 50 1.2.0.5 134 670 50 1.3.10 135 679 2 (cool! :)
19. Use VIEWS instead of complicated SELECTS Are you needing ps_connections & ps_connections_page? If you are expecting high traffic, thay can rise 10+ Mb / day Database
20. Big problem - non unique queries 1.3.10, simulation of command process: Index – search – authentication – order (11 pages total) 3001 SQL queries, but only 1314 uniques! (44%) PHP - SQL
23. Best is use mysql proxy or memcachedNot always possible Do not resolve overhead of unnecessary calls Use internal cacheCan be scoped or globalPrestashop partially uses scoped cacheEasy to implement, tune, and … forget Each method / class is responsable for caching its query results Solutions
24. static public function getCurrency($id_currency){ return Db::getInstance()->getRow('SELECT * FROM `'._DB_PREFIX_.'currency` WHERE `deleted` = 0 AND `id_currency` = '.intval($id_currency)); } static public functiongetCurrency($id_currency){ if (!isset(self::$_cache[$id_currency])) { self::$_cache[$id_currency] = Db::getInstance()->getRow('SELECT * FROM `'._DB_PREFIX_.'currency` WHERE `deleted` = 0 AND `id_currency` = '.intval($id_currency)); } return self::$_cache[$id_currency]; } Scoped cache
34. foreach($cart->getProducts() as $product) if ($orderStatus->logable) ProductSale::addProductSale(intval($product['id_product']), intval($product['cart_quantity'])); Should be: if ($orderStatus->logable) foreach($cart->getProducts() as $product) ProductSale::addProductSale(intval($product['id_product']), intval($product['cart_quantity'])); (no need to test if in every iteration if it does not change) Use conditions wisely
37. We are preparing whole mail, including pdfattachement, even if we are not sending it. Every times you do it, a little kitten dies Non optimised conditions
50. Use Cache (mod_expires, Etags) for static content such as imagesyou can do it in htacces or httpd.conf ExpiresActiveOn ExpiresDefault"access plus 15 days“ ExpiresByTypeimage/gif A2592000 Network
53. Avoid passing HTML / XML as AJAX result. Use JSON instead of. You can reduce amount of data by magnitude of 75% (which if of course faster. Which is of course better). Client-sidestuff
56. Allowsyou to interactwith the database Sanitize all your variables before use in SQL requests!<?php ...... $order_detail = Db::getInstance()->ExecuteS(' SELECT * FROM .'_DB_PREFIX_.'order_detail WHERE id_order='.(int)$_GET['id_order'] AND payment=apos;'.pSQL($_GET['payment']).'apos;'); SQL Injection
57. Exploit the site's trust in your identity Use tokens Requiring authentication in GET and POST parameters index.php?tab=AdminOrders&token=e84b3fda0b04b922b3bc27b08d4fe136 CSRF
58. Inject HTML code in the page Sanitize all your variables before output! <input type="text" name="lastname" value="{$smarty.post.lastname|htmlentities}" /> preg_replace('/.*script/ui', '', $_POST['lastname']); preg_replace('/.*onmousedown|onmousemove|onmmouseup|onmouseover|onmouseout|onload|onunload|onfocus|onblur|onchange|onsubmit|ondblclick|onclick|onkeydown|onkeyup|onkeypress|onmouseenter|onmouseleave/ui', '', $_POST['lastname']); ... XSS
59. Access to unauthorized datas Sanitize all your variables before load files! Check the extention of the file include (dirname(__FILE__).'/mails/'. preg_replace(‘/{2,}/', '.', Tools::getValue('mail')).'html'); Path transversal