In seldom cases, you will need to start looking into efficiency issues with Chamilo. This guide is a work in progress intended to help administrators optimize their Chamilo installation.
xcache.shm_scheme = "mmap" xcache.size = 32M xcache.count = 2 xcache.slots = 8K xcache.ttl = 0 xcache.gc_interval = 0 xcache.var_size = 16M xcache.var_count = 16 xcache.var_slots = 8K xcache.var_ttl = 60 xcache.var_maxttl = 300 xcache.var_gc_interval = 300 xcache.test = OffxCache will feel useless until you actually start to put some variables in cache. If you're showing the "Who is online" counter, that's one of the best item there is to implement xCache.
$xc = function_exists('xcache_isset'); $number = 0; if ((api_get_setting('showonline', 'world') == 'true' AND !$user_id) OR (api_get_setting('showonline', 'users') == 'true' AND $user_id) OR (api_get_setting('showonline', 'course') == 'true' AND $user_id AND $course_id)) { if ($xc && xcache_isset('campus_chamilo_org_whoisonline_count_simple')) { $number = xcache_get('campus_chamilo_org_whoisonline_count_simple'); } else { $number = who_is_online_count(api_get_setting('time_limit_whosonline')); xcache_set('campus_chamilo_org_whoisonline_count_simple',$number); } } $number_online_in_course = 0; if(!empty($_course['id'])) { if ($xc && xcache_isset('campus_chamilo_org_whoisonline_count_simple_'.$_course['id'])) { $number_online_in_course = xcache_get('campus_chamilo_org_whoisonline_count_simple_'.$_course['id']); } else { $number_online_in_course = who_is_online_in_this_course_count(api_get_user_id(), api_get_setting('time_limit_whosonline'), $_course['id']); xcache_set('campus_chamilo_org_whoisonline_count_simple_'.$_course['id'],$number_online_in_course); } }Note that, as xCache is a shared caching system, it is very important to prefix your variables with a domain name or some kind of identifier, otherwise it would end up in disaster if you use a shared server for several portals.
global $_configuration; $_course = api_get_course_info(); $course_id = api_get_course_id(); $user_id = api_get_user_id(); $html = ''; $xc = method_exists('Memcache','add'); if ($xc) { // Make sure the server is available $xm = new Memcache; $xm->addServer('localhost', 11211); $xc = $xc && ($xm->getServerStatus('localhost',11211)!=0); // The following concatenates the name of the database + the id of the // access url to make it a unique variable prefix for the variables to // be stored $xs = $_configuration['main_database'].'_'.$_configuration['access_url'].'_'; } $number = 0; if ((api_get_setting('showonline', 'world') == 'true' AND !$user_id) OR (api_get_setting('showonline', 'users') == 'true' AND $user_id) OR (api_get_setting('showonline', 'course') == 'true' AND $user_id AND $course_id)) { if ($xc && $xm->get($xs.'wio_count_simple')) { $number = $xm->get($xs.'wio_count_simple'); } else { $number = who_is_online_count(api_get_setting('time_limit_whosonline')); $xm->set($xs.'wio_count_simple',$number,0,30); } $number_online_in_course = 0; if(!empty($_course['id'])) { if ($xc && $xm->get($xs.'wio_count_simple_'.$_course['id'])) { $number_online_in_course = $xm->get($xs.'wio_count_simple_'.$_course['id']); } else { $number_online_in_course = who_is_online_in_this_course_count($user_id, api_get_setting('time_limit_whosonline'), $_course['id']); $xm->set($xs.'wio_count_simple_'.$_course['id'],$number_online_in_course,0,30); } }
$xc = function_exists('apc_exists'); $number = 0; if ((api_get_setting('showonline', 'world') == 'true' AND !$user_id) OR (api_get_setting('showonline', 'users') == 'true' AND $user_id) OR (api_get_setting('showonline', 'course') == 'true' AND $user_id AND $course_id)) { if ($xc) { $apc = apc_cache_info(null,true); $apc_end = $apc['start_time']+$apc['ttl']; if (apc_exists('my_campus_whoisonline_count_simple') AND (time() < $apc_end) AND apc_fetch('my_campus_whoisonline_count_simple') > 0 ) { $number = apc_fetch('my_campus_whoisonline_count_simple'); } else { $number = who_is_online_count(api_get_setting('time_limit_whosonline')); apc_clear_cache(); apc_store('my_campus_whoisonline_count_simple',$number,15); } } else { $number = who_is_online_count(api_get_setting('time_limit_whosonline')); } $number_online_in_course = 0; if (!empty($_course['id'])) { if ($xc) { $apc = apc_cache_info(null,true); $apc_end = $apc['start_time']+$apc['ttl']; if (apc_exists('my_campus_whoisonline_count_simple_'.$_course['id']) AND (time() < $apc_end) AND apc_fetch('my_campus_whoisonline_count_simple_'.$_course['id']) > 0) { $number_online_in_course = apc_fetch('my_campus_whoisonline_count_simple_'.$_course['id']); } else { $number_online_in_course = who_is_online_in_this_course_count($user_id, api_get_setting('time_limit_whosonline'), $_course['id']); apc_store('my_campus_whoisonline_count_simple_'.$_course['id'],$number_online_in_course,15); } } else { $number_online_in_course = who_is_online_in_this_course_count($user_id, api_get_setting('time_limit_whosonline'), $_course['id']); } } ...
It is also worth noting that the Université de Genève, Switzerland, observed that the calculation of the total size used by course documents is one of the heaviest queries in Chamilo, so you might want to cache the results of this one as well, using the same technique.
Finally, if your portal is highly public *and* you are showing the popular courses on the homepage, you might want to also reduce the amount of queries this generates, using the same technique as above, but for the main/inc/lib/auth.lib.php library, looking for the "Tracking::get_course_connections_count()" call:
while ($row = Database::fetch_array($result)) { $row['registration_code'] = !empty($row['registration_code']); $count_users = CourseManager::get_users_count_in_course($row['code']); $xc = function_exists('apc_exists'); if ($xc) { $apc = apc_cache_info(null, true); $apx_end = $apc['start_time']+$apx['ttl']; if (apc_exists('my_campus_course_visits_'.$row['code']) AND (time() < $apc_end) AND apc_fetch('my_campus_course_visits_'.$row['code']) > 0) { $count_connections_last_month = apc_fetch('my_campus_course_visits_'.$row['code']); } else { $count_connections_last_month = Tracking::get_course_connections_count($row['code'], 0, api_get_utc_datetime(time() - (30 * 86400))); apc_store('my_campus_course_visits_'.$row['code'], $count_connections_last_month, $apc['ttl']); } } else { $count_connections_last_month = Tracking::get_course_connections_count($row['code'], 0, api_get_utc_datetime(time() - (30 * 86400))); } ... }
ALTER TABLE lp_item ADD INDEX idx_c_lp_item_cid_lp_id (c_id, lp_id); ALTER TABLE lp_item_view ADD INDEX idx_c_lp_item_view_cid_lp_view_id_lp_item_id (c_id, lp_view_id, lp_item_id);These will be available in Chamilo 1.10 directly, but we cannot put them into Chamilo 1.9 from now on for organizational reasons.
php_value zlib.output_compression 1
AddOutputFilterByType DEFLATE text/html text/plain text/xmlor, for every content type (dangerous) you can put the following inside a location or directory block:
SetOutputFilter DEFLATE
# Insert filter SetOutputFilter DEFLATE # Netscape 4.x has some problems... BrowserMatch ^Mozilla/4 gzip-only-text/html # Netscape 4.06-4.08 have some more problems BrowserMatch ^Mozilla/4\.0[678] no-gzip # MSIE masquerades as Netscape, but it is fine # BrowserMatch \bMSIE !no-gzip !gzip-only-text/html # NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48 # the above regex won't work. You can use the following # workaround to get the desired effect: BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html # Don't compress images SetEnvIfNoCase Request_URI \ \.(?:gif|jpe?g|png)$ no-gzip dont-vary # Make sure proxies don't deliver the wrong content Header append Vary User-Agent env=!dont-vary
$platform_email['SMTP_MAILER'] = 'smtp';or
$platform_email['SMTP_MAILER'] = 'mail';In fact, the complete loading of mail.conf.php can also be avoided if loaded conditionally (with require_once) when sending an e-mail (which is the only case where it is useful).
It might have come to your attention that file downloads through Chamilo might get slow, under default conditions, in particular using Apache 2.
There are several ways to fix this, one of which is removing the .htaccess inside the courses/ directory. This, however, will remove all permissions checks on the files contained in this directory, so... most of the time, not ideal unless your portal is *really* open to the world.
Another technique, revealed to us by VirtualBlackFox on this Stackoverflow post, is to use the X-SendFile module for Apache 2.2+ (other web servers might offer other solutions, or avoid the problem initially).
Installing the X-SendFile module will depend on your operating system, but if you use Ubuntu, you'll have to check you are including the "universe" repository inside your packages sources (check /etc/apt/sources.list), then:
sudo apt-get update sudo apt-get install libapache2-mod-xsendfile sudo service apache2 restartOnce you're done with installing, you'll have to configure Chamilo to use it.
sudo vim /etc/apache2/sites-available/my.chamilo.net.conf # add the following line: X-SendFile on # exit the file sudo service apache2 reloadFinally, you'll have to got to your Chamilo configuration file, and add the following line at the very bottom of the file main/inc/conf/configuration.php:
$_configuration['enable_x_sendfile_headers'] = true;Done! Now your downloads should go substantially faster. This is still a feature in observation. We're not sure the benefits are sufficient, so don't hesitate to let us know in the related issue in Chamilo's tracking system