21 Feb

Turn your normal CakePHP forms to AJAX forms in a second

Best Practices, CakePHP, jQuery

CakePHP helpers are so powerful that when you begin to hack helpers here and there you discover a lot of possibilities which can save you a lot of time. Same thing happened when I had an idea to AJAX'ify the forms using some shortcut.

Let's try hacking the FormHelper and enable AJAX. We'll use jQuery Form plugin to submit forms via AJAX request (I don't know any other good plugins for forms).

What we'll be doing:

Converting a normal form like below one, to make it call AJAX(using jQuery lib) and alert us when form posted:

PHP:
  1. <div class="jerks form">
  2. <?php echo $form->create('Jerk');?>
  3.     <fieldset>
  4.        <legend><?php __('Add Jerk');?></legend>
  5.     <?php
  6.         echo $form->input('name');
  7.     ?>
  8.     </fieldset>
  9. <?php echo $form->end('Submit');?>
  10. </div>

 

1. Extend your FormHelper to something like AjaxFormHelper (Now normally I don't extend core helpers like this, but use a similar method similar to this (comment by grigri): http://cakebaker.42dh.com/2008/10/18/dont-abuse-the-apphelper-to-extend-the-core-helpers/#comment-110708 ) and overwrite create() method like this:

PHP:
  1. function create($model = null, $options = array())
  2. {
  3.     $output = "";
  4.     if(isset($options['ajax']) && $options['ajax']=='true')
  5.     {
  6.         if(!isset($options['id']))
  7.         {
  8.             $options['id'] = 'form' . intval(mt_rand());
  9.         }
  10.        
  11.         $this->ajaxForm = $options['id'];
  12.         $url = "$('#".$options['id']."').attr('action')+'?ajax=1&flash_only=1";
  13.        
  14.         if(@$options['response']=='inline')
  15.         {
  16.             $datatype = 'text';
  17.             $success = "$('#".$options['id']."_status').hide().html(responseText).fadeIn();
  18.                         setTimeout(function(){
  19.                             $('#".$options['id']."_status').fadeOut();
  20.                         }, 5000);";
  21.             $url .= "&js=false'";
  22.         }
  23.         else {
  24.             $datatype = 'script';
  25.             $success = '';
  26.             $url .= "'";
  27.         }
  28.        
  29.         // to-do: avoid multiple inclusion of this script
  30.         $output .= "<div id='".$options['id']."_status' style='display:none;'></div>";
  31.         $output .= "<script src='".$this->Html->url('/effects/js/jquery.form.js')."'></script>";
  32.         $output .= "<script>
  33.         $(document).ready(function() {
  34.         $('#".$options['id']."').ajaxForm({dataType: '".$datatype."', url:  ".$url.",
  35.             beforeSubmit: function(){
  36.             $('#".$options['id']." .submit input').attr('disabled', true);
  37.             $('#progressIndicator').show();
  38.             $('#".$options['id']." .form_progress').show();
  39.             },
  40.             success: function(responseText, statusText){
  41.             $('#".$options['id']." .submit input').attr('disabled', false);
  42.             $('#progressIndicator').hide();
  43.             $('#".$options['id']." .form_progress').hide();
  44.             ".$success."
  45.             },
  46.         });
  47.     });
  48.     </script>";
  49.     }
  50.     // unset js options
  51.     $output .= parent::create($model, $options);
  52.    
  53.     return $this->output($output);
  54. }

I'm not that good in explaining code flow, but you might have noted 3 get variables appended to our form action URL above. These variables are: 'ajax','flash_only' ,'js' and serves their own purpose that I'll tell in next steps.

 

2. Now we enable the AJAX in our form (CakePHP's $options array is so good that you can overwrite and modify almost many methods easily):

This will show a JS alert after form has been submitted successfully.

PHP:
  1. <div class="jerks form">
  2. <?php echo $ajaxForm->create('Jerk', array('ajax'=>'true'));?>
  3.     <fieldset>
  4.        <legend><?php __('Add Jerk');?></legend>
  5.     <?php
  6.         echo $ajaxForm ->input('name');
  7.     ?>
  8.     </fieldset>
  9. <?php echo $ajaxForm ->end('Submit');?>
  10. </div>

This will show an inline message after form has been submitted successfully.

PHP:
  1. <div class="jerks form">
  2. <?php echo $ajaxForm->create('Jerk', array('ajax'=>'true' , 'response'=>'inline'));?>
  3.     <fieldset>
  4.        <legend><?php __('Add Jerk');?></legend>
  5.     <?php
  6.         echo $ajaxForm ->input('name');
  7.     ?>
  8.     </fieldset>
  9. <?php echo $ajaxForm ->end('Submit');?>
  10. </div>

Note that ajax=true parameter we sent in create() method. This will tell helper to load this form via AJAX.

 

3. Now your form will be AJAX ready (if you've included this AjaxFormHelper properly). But because our controller function was made to process normal POST function, and flash message on success – we'll have to change that behavior. This is what a normal JerksController::add() method should look like:

PHP:
  1. function add() {
  2.         if (!empty($this->data)) {
  3.             $this->Jerk->create();
  4.             if ($this->Jerk->save($this->data)) {
  5.                 $this->Session->setFlash('Jerk saved.');
  6.             } else {
  7.             }
  8.         }
  9.     }

We don't need full action content from views/jerks/add.ctp to appear in response when AJAX is called. We can make this work traditional way by checking if it's an AJAX request in controller method itself and do needful, but I wouldn't want to modify all my controller functions to enable AJAX, so here's what I've come up with.

Remember the 3 GET variables above?

'ajax' => This one will determine if a given HTTP request is an AJAX request.

'flash_only' => This will tell if rendering should happen or not. Flash only means, after controller function is executed, do not render, just show flash message.

'js' => This is used for alert type, if this is not set, show inline alert. If set true, helper must show JS alert() on form success.

Inside your AppController::beforeFilter(), add this code:

PHP:
  1. if(isset($_GET['ajax']))
  2. {
  3.     Configure::write('debug',0);
  4.     $this->layout = 'ajax';
  5.     $ this ->set('ajax', true);
  6.     if($_GET['flash_only'])
  7.     {
  8.         $ this ->set('flash_only', true);
  9.         //$ this ->autoRender = false;
  10.     }
  11.    
  12.     if($_GET['js']=='false')
  13.     {
  14.         $ this ->set('js', 0);
  15.     }
  16.     else {
  17.         $ this ->set('js', 1);
  18.     }
  19. }

Do not blame me for using GET variables, I found many issues with 'named' so I'm relying on normal GET variables.

Now you'll need to edit ajax.ctp layout file.

PHP:
  1. <?php
  2. if ($session->check('Message.flash'))
  3. {
  4.     $strMessage = '';
  5.     $message = $session->read('Message.flash');
  6.     if(isset($message['params']['type']))
  7.     {
  8.         $type = $message['params']['type'];
  9.         $strMessage = ucfirst($type).": ".$message['message'];   
  10.     }
  11.     else {
  12.         $strMessage = $message['message'];     
  13.     }
  14.     $session->del('Message.flash');
  15. }
  16. if(!empty($this->validationErrors))
  17. {
  18.     $strMessage = '';
  19.     foreach($this->validationErrors as $model=>$errors)
  20.     {
  21.         foreach($this->validationErrors[$model] as $field=>$error)
  22.         {
  23.             $strMessage .= $error;
  24.         }
  25.     }
  26. }
  27. ?>
  28. <?
  29. if($strMessage) {
  30.     if($js==1) {
  31. ?>
  32.     alert('<?=$strMessage;?>');
  33. <? } elseif($js==0) {
  34.     echo $strMessage;
  35. } } ?>
  36. <?
  37. if(!isset($flash_only))
  38. {
  39.     echo $content_for_layout;
  40. }
  41. ?>

This should be self explanatory, even though this code definitely needs some refactoring. We're basically manipulating those 3 GET variables according to our need. In process, we're also checking validation errors occurred in form.

I have not used it under the production environment yet, so I'd really like to hear any pitfalls (if any) using this approach. Thanks for reading.

Abhimanyu Grover

22 Dec

Security concerns with open source web apps and how to be safe

Best Practices

While a routine research on net today I went to a security advisory site. I was reminded by this website that how easy it is, for script kiddies to hack into most of the outdated open source apps. It's not a new thing, but I feel importance of sharing my experience as a web developer. For instance, this website here has got a special section for web apps featuring latest vulnerabilities and potential security compromises: http://milw0rm.com/webapps.php

If one start browsing through it, will easily find everything from File disclosure attacks to SQL injections. And it's just not that, in most of the reported security issues, people have even published a test script or attacker code which can actually run from anyone's computer increasing number of possible attackers who are not just aware of the flaw, but are provided with the real tools now, to do what they want with a victim website. I've seen many websites went down in huge amount when such vulnerabilities are out in public. One of the biggest vulnerabilities in phpBB, an open source forum, was released few years back. It allowed any attacker to gain shell access to the victim website, and yes, I did tried it on my server before fixing the code. I seen like hundreds of websites went down in a matter of few hours. Later, the flaw was such a big hit to phpBB, that it was named as a worm. You can see BBC news article for stats etc. on it.

My clients ask me, 'this new open source technology is cool; we would like to go with it. What do you think?' I often stop and think for a second. Sometimes, I also try to explain them about positive and negative aspects related to it. I know decision to use open source technology will save time and budget anyway, so I keep decision on them most of the time. But I know it's not as safe as a custom-made app, I believe using something which is accessible to thousands of people comes with its own disadvantages (and advantages too, for that matter).

So should you really stop using Wordpress or Joomla or any other open source tech?

No, and Yes. First, you got to accept a thing. By choosing an open source app, you're keeping yourself a bit opened for attacks somehow – you have to accept that fact. But some good open source projects like Joomla, Wordpress, phpBB and many other with big communities are more responsive to such attacks, in just few hours when such vulnerability is out in public, they release security updates and have good platform to notify people using them. Sometimes these project owners are informed even before the attack is made public itself. Still, you can't trust a community if you are handling sensitive data or sensitive operations with your application. I wouldn't recommend any open source web app to any government institution, never ever for the same reason.

So, Open source with a backup of big community is good enough?

No matter how good a project's community might be or how bad, in any case, you have to keep your eyes open to such new vulnerabilities. If you've just launched an app, and kept it ignored on a server for months, you're likely to get hacked before any other active website. Remember, a good administration is must when using open source web apps. I highly recommend that either you keep an eye on such alerts or let your developers do the job. Like they say, Prevention is better than cure. Being proactive in preventing an attack is much easier rather than getting back online after your app is compromised because of some vulnerability.

What do we recommend?

  • Keep an eye on security updates from project's website
  • Always use the latest stable version of software, and update it timely
  • Keep an eye on advisories boards or such website (Best thing, is to create a Google web alert to let you alert when something like this is out)
  • Timely Automated backups

If you're not already doing it, I highly recommend you getting on it from today if you really care about your website. Hope this helps. Thanks for reading.

- Abhimanyu Grover

19 Nov

Great way to test outgoing emails while developing a web-app

Best Practices

Every web developers uses mail() and spend some time testing if it is working or mail format is right or not. And when you have a big app which has a lot of emails to test, it can eat up a lot of time in testing.

Many developers use SMTP server running on their local host, others use some sort of complicated script, while others might be dependent on external SMTP servers for testing of outgoing mails from their web app. We were also using some sort of SMTP server for testing our outgoing emails, but if you want to see the best way to do so, here's this:

Test Mail Server tool

The program listens on localhost on a SMTP port (usually 25, may be changed). All mail sent to this tool is automatically stored and optionally opened with your mail client.

This cool tool will save you extra time opening your mailbox everytime after you carry out an email test or something. It has worked great for me.

Hire us

Contact us to get a free quote on your project.