I run a busy Slovenian site featuring weather radar image on Google maps - vreme.malamalca.com . It is a simple CakePHP app which collects weather and radar data, stores it in cache and outputs it in friendly format.
Recently my site is receiving some heavy traffic due to high probability of hail storms which are result of high temperatures - around 35° (95°F). Everyone wants to check if their car /or home/ is in immediate danger. Bad weather is causing high spikes of traffic and sluggish response times.
After checking my site with YSlow, it got "F" grade. My site needed some improvements. There are some steps I took which got my site to grade "B" of YSlow:
- I changed my cache engine to APC. This had a tremendous effect in responsiveness of my app (although it is not graded by YSlow)
- Next step was implementation of some Apache directives in .htacces in /webroot folder:
Here are new .htaccess contents:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L]
# compress content with type html, text, and css
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
#AddOutputFilter DEFLATE js css
# properly handle requests coming from behind proxies
Header append Vary User-Agent
ExpiresActive On
ExpiresByType application/javascript "access plus 10 years"
ExpiresByType text/css "access plus 10 years"
ExpiresByType text/js "access plus 10 years"
ExpiresByType text/javascript "access plus 10 years"
ExpiresByType application/x-javascript "access plus 10 years"
ExpiresByType image/png "access plus 10 years"
ExpiresByType image/gif "access plus 10 years"
ExpiresByType image/jpeg "access plus 10 years"
FileETag none
These adjustments made my site usable again even in spikes of 500 users per minute.
Note: some aditional warnings... this directives extend duration of cached items in your browser. You should know what are you trying to achieve.
I hate CakePHP's datetime controls.
Having three (or even five with time) selectboxes for one single date is just to much. I wanted to simplify this process quite some time now. I also wanted a user friendly solution without changing my current code (with default controls). Javascript datepicker (popup) would be the most common solution. Here's my implementation.
- Append a hidden field in every <div class="input date"> element
- This hidden field is converted into jQuery datepicker control
- Two sync routines are added - they take care of populating select elements with values picked from jQuery widget and vice versa
This is how it looks like. Click on calendar icon for javascript popup (it's an image...click on it for live demo page):

Here's the code:
<script type="text/javascript">
$(document).ready(function() {
$('div.date').append('<input class="datepicker" type="hidden"/>');
$('.datepicker').datepicker({
dateFormat: 'yy-mm-dd',
buttonImage: '/uploads/calendar.png',
buttonImageOnly: true,
duration: '',
showOn: 'button',
onSelect: function(sel_date) {
var newDate = sel_date.split('-');
$(this).siblings('select').each(function(){
id = $(this).attr('id');
if (id.substring(id.length-3, id.length)=='Day') $(this).val(newDate[2]);
else if (id.substring(id.length-5, id.length)=='Month') $(this).val(newDate[1]);
else if (id.substring(id.length-4, id.length)=='Year') $(this).val(newDate[0]);
});
},
beforeShow: function() {
var year = '';
var month = '';
var day = '';
var id = '';
$(this).siblings('select').each(function() {
id = $(this).attr('id');
if (id.substring(id.length-3, id.length)=='Day') day = $(this).val();
else if (id.substring(id.length-5, id.length)=='Month') month = $(this).val();
else if (id.substring(id.length-4, id.length)=='Year') year = $(this).val();
});
$(this).val(year+'-'+month+'-'+day);
return {};
}
});
});
</script>
Edit: thanks Shubha for pointing out problem with IE. I've fixed it. Datepicker now works seamlesly in IE too.
LilFloat behavior takes care of your decimal input when your local numeric format differs from US standards.
Most of EU and other countries use comma for decimal separator and dot for thousands. Unfortunatelly CakePHP cannot handle this. Therefore I use this behavior. It automagicaly converts your decimals in a local representation into "default" version which is required for storing decimals into the database.
Wait! There is more. LilFloat behavior has also a validation method for your decimal input. Usage is as simple as adding a new validation rule. Did I mention that it can auto extract decimal places from your field type? Well, it does. Check tests for more samples.
<?php
class YourModel extends AppModel {
var $name = 'YourModel';
var $actsAs = array('LilFloat');
var $validate = array(
'decimalfield' => array(
'format' => array('rule' => 'isValidFloat'),
),
);
}
?>
You can find LilFloat behaviour in my LilCake repository. Enjoy!
I've finally implemented wysiwyg editor for LilBlogs. Currently text editor is still a default editor for posts but it will be replaced (as a default one) with one of the free html editors. For now, you can choose between TinyMCE or FckEditor.
Turning on wysiwyg editing requires two steps:
- download one of the editors mentioned above and extract it in /webroot/js folder (you have to create structure like /webroot/js/tinymce/)
- adding or changing configuration directive LilblogsPlugin.editor - like Configure::write('LilblogsPlugin.editor', 'tinymce');
I am planning to further improvements in this field - like creating editor themes, adding styles and adding file/image/media managers.
Currently I am working on bayesian filtering implementation as CakePHP behavior. I am already using bayesian filtering for comments in LilBlogs system. Currently it categorizes comments in two obvious groups: spam and ham. It just works!
This bayesian filtering is awsome. It works practicly without mistakes on one of my sites with heavier traffic and substential comment count using LilBlogs. The only downside of Bayes filtering is that it needs some learning before it becomes efficient. After this initial faze it gets only better and better.
Stay tuned! I will be releasing LilBayes behaviour shortly.