By Antithesis Group

On the fly javascript compression/optimization on nginx using Google Closure Compiler

06 Μαρτίου 2012

Google closure compiler allows for smaller javascript files that download and run faster. Serving those optimized javascript files instead of the originals and also turning on gzip compression to serve them can save more than 50% on the original size. Other modern web tools today besides Google closure compiler for optimizing/compressing javascript are Yahoo’s YUI Compressor, Dojo Shrinksafe and UglifyJs.

Indeed the minification process (called compilation on google’s closure compiler site) makes your javascript code quite unreadable. A practical approach is to keep 2 versions of each .js file: the uncompressed version (original source – to work) and the minimized/compressed version ( compiled version – to serve).

Using the nginx web server we can automate the compilation of any javascript source files by using Google Closure Compiler without the need to manually run any external tools. Nginx web server will take care of the compilation, keep the compiled version cached and serve this compiled javascript file on future requests.

In our approach, we want to make use of the embedded Perl module that nginx offers. Several major Linux distributions today offer nginx packages configured with the embedded Perl module.

You can already find an example module to minify javascript files on nginx wiki (EmbeddedPerlMinifyJS) that is using the JavaScript::Minifier Perl CPAN module (inspired by Douglas Crockford’s JSMin). This solution is not optimal (compression/savings achieved) and the CPAN module has not been updated for years (JSMin is about 10 years old). Today you can find actively developed javascript compilers/optimizers that are more sophisticated and evolve. Moreover, in our tests with JavaScript::Minifier some UTF-8 .js files were not minified correctly. Google closure compiler is a better choice today since it is well known, tested, up to date and quite advanced as a javascript compiler/optimizer.

The good news? Google Closure compiler offers a RESTful API…
Even better news? You can find an already working Perl interface for this service on CPAN!

Let’s get started

First, make sure that nginx has been configured and compiled with the Perl module (configured “–with-http_perl_module”). You can run the command “nginx -V” to check. Here is a sample output of the command on a Centos 6 Linux:

# nginx -V
nginx version: nginx/0.8.54
built by gcc 4.4.4 20100726 (Red Hat 4.4.4-13) (GCC)
TLS SNI support enabled
configure arguments: --user=nginx --group=nginx --prefix=/usr/share/nginx 
--sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf 
--error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log
--http-client-body-temp-path=/var/lib/nginx/tmp/client_body 
--http-proxy-temp-path=/var/lib/nginx/tmp/proxy 
--http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi 
--http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi 
--http-scgi-temp-path=/var/lib/nginx/tmp/scgi 
--pid-path=/var/run/nginx.pid --lock-path=/var/lock/subsys/nginx
--with-http_ssl_module --with-http_realip_module --with-http_addition_module
--with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module
--with-http_sub_module --with-http_dav_module --with-http_flv_module
--with-http_gzip_static_module --with-http_random_index_module 
--with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module
--with-http_perl_module --with-mail --with-file-aio --with-mail_ssl_module --with-ipv6
--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector
--param=ssp-buffer-size=4 -m64 -mtune=generic' --with-cc-opt='-O2 -g -pipe -Wall
-Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 
-m64 -mtune=generic'

As you can see above our nginx there is already configured “–with-http_perl_module”. Also note on the first line the –prefix (it is /usr/share/nginx), we will use it in a while.

Now, you should install WebService::Google::Closure from CPAN on your system or do a manual module installation.

A quick note for those not familiar with CPAN (assuming a Linux install): Enter “perl -MCPAN -e shell” as root (or the command “cpan”). If this is your first time running cpan there might be some setup questions. When you get the cpan shell, enter: “install WebService::Google::Closure”. Say yes to install any required depedencies on your system. After installing the module type “exit” to return to your shell.

The Perl handler

As a next step, let’s write our handler module. We will create the new file (Perl code) in a subdirectory of the —prefix directory mentioned above (actually we will create a new directory “perl_handlers” there just to keep things tidy).

File JSClosureCompiler.pm (save into /usr/share/nginx/perl_handlers):

package JSClosureCompiler;
use nginx;
use WebService::Google::Closure;

#to make sure we write UTF-8 files
use open OUT => ':utf8';

sub handler {
  my $r=shift;
  my $cache_dir="/tmp";  # Cache directory where optimized files will be kept
  my $cache_file=$r->uri;
  $cache_file=~s!/!_!g;
  $cache_file=join("/", $cache_dir, $cache_file);
  my $uri=$r->uri;
  my $filename=$r->filename;
  return DECLINED unless -f $filename;

  if (! -f $cache_file) {
    my $minjs = WebService::Google::Closure->new(file => $filename)->compile;
    open(OUTFILE, '>' . $cache_file ) or die "Error writting file: $!";
    print OUTFILE $minjs->code;
    close(OUTFILE);
  }
  $r->send_http_header("application/javascript");
  $r->sendfile($cache_file);
  return OK;
}
1;
__END__

As you can see the optimized files are cached in $cache_dir (“/tmp” here) to avoid optimizing the same files again in every web request (of course this should be avoided – better serve your uncompressed .js files in that case!). An underscore character is prepended on cached files filenames.

If you need to regenerate an optimized javascript file (after updating your javascript source code for example), just delete the cached file from /tmp (it will be regenerated fresh on the next request of this file by nginx).

The nginx side

To use our handler on nginx, you should update your nginx.conf:

http {
  perl_modules perl_handlers; #our newly created directory
  perl_require WebService/Google/Closure.pm;
  perl_require JSClosureCompiler.pm; 

  root /var/www;
  server {
    location / {
      ....
    }

    location ~ \.js$  {
       perl JSClosureCompiler::handler;
    }
  } 
}

Magic happens of course at the location ~ .js$ {…} block, where we pass all our .js files to our custom Perl handler. Reload nginx afterwards to reread your configuration.

You can now load a .js file on your browser and enjoy freshly optimized javascript being served. Of course you should test any applications you may already serve with the optimized javascript.

How to control the aggressiveness of the javascript compiler

You can control how aggressive the javascript compiler will be. The line:

my $minjs = WebService::Google::Closure->new(file => $filename)->compile;

uses the default ‘simple optimizations’ as defined by Google Closure Optimizer.

For whitespace removal only, you can use:

my $minjs = WebService::Google::Closure->new(
                                              file => $filename, 
                                              compilation_level => 1,
                                             )->compile;

and for “advanced optimizations” just change the compilation_level above to 3.

I try to syntax check my module by using “perl -c” and I get an error about an “undefined symbol”.

In syntax checking of Perl scripts all “use” statements are still executed. Do not “use nginx;” outside nginx. Everything will be ok when running inside nginx. If this is the only error you get, go ahead and try it inside nginx.

Επεξεργασία εικόνας μέσω PHP

19 Απριλίου 2007

Στο άρθρο αυτό βλέπουμε βασικές δυνατότητες που προσφέρουν σήμερα οι πιο γνωστές βιβλιοθήκες επεξεργασίας εικόνας και στη συνέχεια δίνουμε πρακτικά βασικά παραδείγματα χρήσης στη γλώσσα προγραμματισμού PHP.

Πριν προχωρήσουμε με τις βιβλιοθήκες επεξεργασίας εικόνας, μια απορία που εύλογα μπορεί να προκύψει είναι “Ποιά η χρησιμότητα τέτοιων βιβλιοθηκών, αφού σήμερα έχουμε στη διάθεσή μας ισχυρότατα προγράμματα όπως το Gimp, το Photoshop και πολλά άλλα για επεξεργασία εικόνας; Τί τις θέλει κανείς αυτές τις βιβλιοθήκες λοιπόν;”

Οι βιβλιοθήκες αυτές έρχονται να εξυπηρετήσουν τις ανάγκες επεξεργασίας εικόνας, είτε σε μια εφαρμογή που αναπτύσσετε είτε κατά τη μαζική επεξεργασία μεγάλου αριθμού εικόνων. Διαβάστε ολόκληρο το άρθρο »

SQL injections (μέρος 1ο)

15 Ιανουαρίου 2007

Στο άρθρο θα ασχοληθούμε με τα SQL injections (έγχυση SQL). Τα SQL injections είναι μια διαδεδομένη μέθοδος επίθεσης σε εφαρμογές web που χρησιμοποιούν συστήματα βάσεων δεδομένων.

Με τη μέθοδο των SQL injections κακόβουλοι χρήστες επιδιώκουν να εκμεταλλευτούν ευπάθειες στην ασφαλεία μιας εφαρμογής web, ώστε να επέμβουν στα δεδομένα της βάσης. Ως μέθοδος επίθεσης δεν είναι νέα ούτε πολύπλοκη. Για την εφαρμογή των SQL injections αρκεί απλά ένας web browser και κοινή λογική – έτσι οι επιθέσεις SQL injections εμφανίστηκαν ταυτόχρονα με τις πρώτες εφαρμογές web.

Σε αυτό το πρώτο μέρος του άρθρου θα ασχοληθούμε με την παρουσίαση των SQL injections – τί είναι και πώς γίνονται, με σκοπό την κατανόηση του προβλήματος. Στο δεύτερο μέρος του άρθρου θα δούμε τρόπους αντιμετώπισης του προβλήματος σε διαφορετικές γλώσσες προγραμματισμού, δηλαδή πώς μπορούμε να αποφύγουμε τη συγκεκριμένη ευπάθεια σε εφαρμογές web που αναπτύσσουμε.

Διαβάστε ολόκληρο το άρθρο »

MySQL, PHP και Ελληνικά (Μέρος 1ο)

16 Νοεμβρίου 2006

Στο άρθρο αυτό καλύπτουμε πρακτικά μέσω ενός παραδείγματος τη χρήση ελληνικών χαρακτήρων στη βάση δεδομένων MySQL και ειδικά την περίπτωση εγγραφής και ανάγνωσης στη βάση μέσω της γλώσσας PHP, ώστε να λειτουργούν σωστά τα Ελληνικά στις εφαρμογές σας.

Επειδή ο τρόπος που χειρίζεται η MySQL τα διάφορα σετ χαρακτήρων (character sets) άλλαξε από την έκδοση 4.1 της MySQL και μετά, στο άρθρο θα καλυφθούν συνολικά οι εξής 3 περιπτώσεις:

  • Χρήση ελληνικών χαρακτήρων σε MySQL version < 4.1
  • Χρήση ελληνικών χαρακτήρων σε MySQL version 4.1 +
  • Migration (μεταφορά) υπάρχουσας βάσης δεδομένων από MySQL version < 4.1 σε MySQL version 4.1 +

Σε αυτό το 1ο μέρος του άρθρου καλύπτουμε τις 2 πρώτες περιπτώσεις, ενώ η 3η περίπτωση θα ακολουθήσει στο 2ο μέρος του άρθρου. Διαβάστε ολόκληρο το άρθρο »