Thursday, October 15, 2009

a Javascript function to manage function timeout

Today I worked with form validations and AJAX requests associated with the event keyup in the input fields.
Sometimes the validation requires an AJAX call (for instance to check if the typed text already exists in the DB). In order to avoid a request for each char typed, a good solution might be using set/clearTimeout.

With the aim of doing only one function to manage all the timeouts of the functions called for each field, I've written a general function that does that, supporting dynamically the function name.

It uses an array (member of the function) to store the timeouts of the functions called, and an eval to launch/stop the each function with the relative timeout.

Tested only on Firefox 3.5.2



/*javascript*/

function callTimeout(funcName, timeout, args) {
if (args==undefined) {args = "";}
if (timeout == undefined) { timeout=500; }

if (this.timeOutsArray == undefined) {
this.timeOutsArray = new Array(); }
if (this.timeOutsArray[funcName] == undefined) {
this.timeOutsArray[funcName] = 0;
}
if (this.timeOutsArray[funcName]) {
clearTimeout(this.timeOutsArray[funcName]);
}
eval("this.timeOutsArray['"+funcName+"'] = setTimeout('" + funcName + "("+args+")', "+timeout+");");
}



Example of use with JQuery:



$("#field1").keyup(function(){callTimeout("validatefield1",500);})
...
...
$("#anotherFieldN").keyup(function(){callTimeout("validatefieldN",500);})







Behaviour: If the user types very quickly in the search box (id=field1), the function is not called hundreds time, but just at the end after 500ms.

Monday, October 12, 2009

printing the backtrace in a complex PHP application

the PHP debug_backtrace [man] function is very useful to understand where a function/method is called.

It prints the back trace of the code.

Example: In the framework I'm currently using there are ORM classes to access the DB. So, it takes long to understand where the query is launched when needed. Solution: save in a global variable (or in a field of the class) the list of the queries launched and the code that has launched each query.


Code:


class DB {
# ...
public function query($query) {
if (
DEBUG_MODE) { ##
$_dbt = debug_backtrace();
$_fromFile = isset( $_dbt[0]['file']) ? str_replace(_ROOT, "",$_dbt[0]['file']) : "";
$_fromLine = isset( $_dbt[0]['line']) ? $_dbt[0]['line'] : "";
$_launchedFrom = "launched from $_fromFile:$_fromLine";
$this->logQueries[] = "[$query][$_launchedFrom]";
# ..query.
}
}
# ...
}



Example of result:


Array
(
[
0] => [set names utf8][launched from C:\wamp\www\dev\index.php:68]
[
1] => [SELECT * FROM `Setting` WHERE `id` = 1][launched from \class\Setting.class.php:20]
[
2] => [SELECT id FROM `User`WHERE id = 293968 LIMIT 1][launched from \class\User.class.php:598]
[
3] => [SELECT * FROM `User` WHERE `id` = 293968][launched from \class\User.class.php:45]
[
4] => [SELECT f.store_id FROM `Store_Monthly_Featured` f ORDER BY f.order ASC][launched from \class\Store_Monthly_Featured.class.php:16]
)


Useful function to print only line and number


function debug_backtrace_filelines() {

$ret = array();
$b = debug_backtrace();
foreach (
$b as $elements) {
$ret[] = $elements['file'].':'.$elements['line'];
}
}

How to search complex source code using regular expressions

Today I needed to search the source code that ware calling a function with a complex array of parameters

URL::Make( 'site/store.inc.php', array( 'action'=>'view','id'=> [... STH...] ,'idTwo'=> [... STH...] ) );

Considering this requirements:

- there are lots of similar function (to exclude from the search) with an argument less or an argument more

- there may are additional spaces in the line

- some other delopers have probably used double quotes instead of single quotes for array keys

- the value of the keys may be a PHP code

- every function call is in one line

An elegant solution is to search using regular expression. Netbeans (my favorite editor) supports POSIX extended regular expression and is very quickly to search a complex epression in a huge amount of source code.

Solution 1

#using char length and patter ".{0,MAX}" (that is: every sequence, MAX maximum chars). Easy !

URL::Make.{0,10}site/store.{0,40}action.{0,9}view.{0,20}id.{0,200}idTwo.{0,30}\).{0,10}\)

Solution 2

#using regexpr for separators. more complex. more accurate in some cases but fails in some cases (eg: comments inside)

URL::Make.*\([ ]*['"]site/store.inc.php['"][ ]*,[ ]*array[ ]*\([ ]*['"]action['"][ ]*=>[ ]*['"]view['"][ ]*,[ ]*['"]id['"][ ]*=>.{0,100}['"]idTwo['"][ ]*=>.{0,100}[ ]*\)[ ]*\)

An idea for DB server load balancing

If the application has a heavy load of reading queries and there are no problems with the application requirements,
a simple possible idea to balance the db server loading is to run the INSERT/UPDATE/ALTER queries in all the servers and run the SELECT queries in just one server (chosen randomly).
Have a look at the 'loadBalancedQuery' function: if the query modifies the db it will be executed in both server, otherwise in just one.

class BalancedDB extends Mysqli {

private function queryServer($query, $server = "mainServer" ) {
$db = DB::GetInstance($server);
return
$db->query();
}

public function
loadBalancedQuery($query) {
if (
preg_match("/[]*(insert|INSERT|update|UPDATE|alter|ALTER).*/",
$query)){
$this->queryServer( $query, "mainServer" );
$this->queryServer( $query, "secondaryServer" );
} else {
$this->queryServer( $query, rand(0,1) ? "mainServer": "secondaryServer" );
}
}

}

Sunday, October 11, 2009

UTF8 in LAMP applications: overview and how to solve the common issues

The problem
In a LAMP application the text is frequently saved/retrieved from/to a database and files. We must consider all the different encoding (mapping characher-byte value): latin1 iso8859-1, latin9, UTF-8 (utf8) etc...
Lots of applications use ISO8859 encoding and some PHP functions to convert the characters (htmlentities, htmlspecialchars etc...)


The solution
Converting all the text from an encoding to another using PHP functions is unsafe, difficult and annoying.
Ad example the character "é" (encoded as iso8859) will printed as "é" if it's supposed to be encoded as utf8.
The solution is to use only one charset for files, Content-Type of the pages and the db. UTF-8 [wiki] is the best choice: a variable-lenght char encoding for the standard Unicode. If you use this charset in the HTML file, it won't need to convert the characters to the respective entities.

How To use UTF-8
  • set your IDE to save and open source files using utf8 encoding
  • set the content-type of your application to utf-8 (better a apache/htaccess rule instead of the meta tag).
  • set the database server to use utf8 encoding (also tables must be converted). If the db is utf8 but client encoding is latin1, execute first of all the query "SET NAMES utf8"
  • if the application was using latin1 and PHP convert functions, remove all the existing function to encode/decode special characters/entities.

 

PHP and tips|PHP