Thứ Sáu, 25 tháng 2, 2011

Excecute query with array param in jdo

Cách excecute một câu query với nhiều tham số truyền vào trong jdo

Cú pháp cho một trường hợp cụ thể khi lấy data :


//pm : PersistenceManager
Query query_variable_name =  pm.newQuery(class_name.class);
//thêm các điều kiên. của câu query ở đây cho phù hợp với yêu cầu của đầu bài
query.setFilter("property_name1 (điều kiện : == or || or > or <...) property_name1Param && property_name2 (điều kiện: == or || or > or <...) property_name2Param");
// khai báo các biến và kiểu dữ liệu của biến
query.declareParameters("dataType property_name1Param, dataType property_name2Param");
//Khai báo mảng và chứa các tham số sẽ dùng trong câu truy vấn vào mảng khai báo
Object [] params_variable_name = {value_param1,value_param2};
//chạy câu query với tham số truyền vào là một array các params
List<ObjectType> articlesCate = (List<ObjectType>) pm.newQuery(query_variable_name).executeWithArray(params_variable_name);


Ví dụ :



// select các trường trong Article
Query querySameCategory = pm.newQuery(Article.class);
// set điều kiện lọc cho category và date
querySameCategory.setFilter("category == categoryParam && date < dateParam");
//sắp xếp theo chiều giảm dần
querySameCategory.setOrdering("date desc");
// lấy 13 bản ghi trong khoảng từ 0 đến 12
querySameCategory.setRange("0,12");
//khai báo kiểu dữ liệu là String và Date lần lượt cho 2 tham số truyền vào arrayParam
querySameCategory.declareParameters("String categoryParam,java.util.Date dateParam");
//Khai báo mảng dữ liệu và set giá trị cho tham số trong mảng
Object [] params = {articles.get(0).getCategory(),articles.get(0).getDate()};
//Chạy câu truy vấn với tham số truyền vào là 1 mảng các tham số
List<Article> articlesCate = (List<Article>) pm.newQuery(querySameCategory).executeWithArray(params);

Hết! ^^

Thứ Hai, 21 tháng 2, 2011

Tự tạo plugin với jquery

Khi viết các ứng dụng sử dụng jquery hay với bất kỳ một ngôn ngữ nào khác , thì việc sử dụng lại code là một điều khá quan trọng, Với jquery bạn có thẻ tự tạo các plugin mà sau này chỉ cần gọi lại plugin là bạn có thẻ sử dụng được.

Bài viết này được tham khảo tại : http://docs.jquery.com/Plugins/Authoring.

Mình có một vd sau:

<html>
<head>
<script type="text/javascript" src='jquery.js'></script>
<script type="text/javascript">
(function(){
pos={
start:0,
stop:500
};
var methods = {
abc:function(poss){
var obj = $.extend(pos,poss);
this.animate({
left:obj['stop']+"px"
},1000).animate({
left:obj['start']+"px"
},1000);
}
};
$.fn.demo = function(method,pos){
if(methods[method]){
return methods[method].apply(this,Array.prototype.slice.call(arguments,1));
}
};
})(jQuery);

$(document).ready(function(){
$('#click').click(function(){
setInterval(function(){
$("#test").fadeIn().demo("abc",{start:"100",stop:"900"});
},2001);
});
});
</script>
</head>
<body>
<div id='test' style="position:absolute;width:100px;height:100px;background:red;display:none;">test cai nao</div>
<a href="#" id='click'>click</a>
</body>
</html>

Ở vd này mình tạo ra một hàm demo ,hàm này sẽ nhận phương thức  va thuộc tính truyền vào(thuộc tính có thể tam hiểu là các đối số mà bạn muốn truyền vào.

Ở vd trên mình truyền vào phương thức abc và thuộc tính poss co hai giá trị la start và stop.Hàm demo sẽ có nhiệm vụ kiểm tra xem phương thức truyền vào có không và gọi phương thức đó nếu nó tồn tại.

if(methods[method]){ //kiểm tra phương thức
return methods[method].apply(this,Array.prototype.slice.call(arguments,1)); //gọi phương thức

Đoạn dài ngoằng ở sau .apply(this,Array.prototype.slice.call(arguments,1)); đây là đoạn truyền tham số cho phương thức abc (arguments,1) xác nhận thược tính poss là tham số truyền vào cho phương thức abc(vì pos ở vị trí số 1,số 0 tính từ method),giả sử sau poss có poss1 thi muốn truyền poss1 bạn thay số 1 thành 2 la ok :).

Bây giơ tạo ra phương thưc abc bằng khai báo.

var methods ={abc:function(poss){}};

var obj = $.extend(pos,poss); dòng này xác nhận xem có tham số truyền vào abc hay không.Nếu có thì nhận tham số truyền vào,không thi lấy giá trị mặc định.Các dòng khác chắc minh không cần giải thích gì thêm vì nó đã quá wen thuộc rồi :D.

Chúc các bạn thành công :D.

Thứ Sáu, 18 tháng 2, 2011

Loại bỏ tag thừa khi crawler.

Khi tiến hành crawler tin chúng ta thường gặp một số vấn đề về thiếu thẻ đóng và mở do  các trang web viết code không chuẩn. Với những bài viết này có thể làm vỡ giao diện của bạn,nhất là việc thiếu thẻ đóng <div> hoặc <b>.Hàm check_tag giúp loại bỏ những thẻ thiếu thẻ đóng hoặc mở,đảm bảo lượng thẻ đóng và mở bằng nhau.Tuy nhiên với các thẻ lồng thì không hiệu quả cho lắm :D (vd:<table>,<ul>).Do cơ chế loại bỏ thẻ đóng và mở không hợp với các loại thẻ này :( . Bác nào có cách giải quyết với các thẻ này thì cho ý kiến nhé :D.

Tham số truyền vào hàm :

+ $str : là đoạn html truyền vào để loại bỏ thẻ.

+ $list_tag: danh sách các thẻ cần loại bỏ thẻ thiếu

vd: ta gọi hàm check_tag("<div>abc<b>tét ne :D</b>",array("div","b"))

function check_tag($str,$list_tag = array())
{
foreach($list_tag as $k=>$v)
{
$str = preg_replace("/[<]{1}[\/]{1}[ ]*({$v}){1}[ ]*[(>)]{0,1}/","</$v>",$str);
$arr[$k] = preg_split("/[(<)]{1}[ ]*({$v}){1}[ a-zA-Z \'\"=;:]*[(>)]{1}/",$str);

$arr1[$k] = preg_split("/[<]{1}[\/]{1}[ ]*({$v}){1}[ ]*[(>)]{1}/",$str);
if(count($arr[$k]) > count($arr1[$k]))
{
$key = count($arr[$k]) - count($arr1[$k]);

$count = count($arr[$k]);
for($i=0;$i < $key;$i++)
{
$save[$k][] = $arr[$k][($count-$i-1)];

unset($arr[$k][($count-$i-1)]);
}
if(!empty($save[$k]))
{
$str = implode("<".$v.">",$arr[$k]).implode('',$save[$k]);
} else {
$str = implode("<".$v.">",$arr[$k]);
}
}

if(count($arr[$k]) < count($arr1[$k]))
{
$key = count($arr1[$k]) - count($arr[$k]);

$count = count($arr1[$k]);
for($i=0;$i < $key;$i++)
{
$save[$k][] = $arr1[$k][($i)];

unset($arr1[$k][($i)]);
}

if(isset($save[$k]))
{
$str = implode('',$save[$k]).implode("</".$v.">",$arr1[$k]);
} else {
$str = implode("</".$v.">",$arr1[$k]);
}
}
}
return $str;
}

Thứ Năm, 17 tháng 2, 2011

Hiển thị tiếng việt khi lập trình php với oracle

Khi sử dụng OCI cần truyền tham số charset vào hàm oci_connect :

$link = oci_connect("$db_user", "$db_pass", "$tns", "AL32UTF8");

Một số tip khác nếu vẫn không khắc phục được :
- Tạo biến môi trường
NLS_LANG = AMERICAN_AMERICA.UTF8
-enable-mbstring trong php config php.ini (hoặc khi biên dịch)
sau đó config :
mbstring.internal_encoding =UTF-8
mbstring.func_overload=7
default_charset =UTF-8
trong file php.ini .

Cuối cùng ... check cái thẻ meta nhé , vớ vẩn lội lại nằm ở đây đấy .

Thứ Hai, 14 tháng 2, 2011

Xây dựng ứng dụng php phân tán với gearman

Lập trình PHP thì có mấy cái khó .

- Phân tán

Làm thế nào để có 1 công việc A , có thể chia nhỏ và chạy phân tán trên các máy tính khác nhau ?

- Bất đồng bộ

Làm thế nào thực hiện một công việc A , nhưng không cần ngay kết quả trả về , công việc có thể tiến hành xong mới thông báo với lời gọi hàm ?

- Xử lý dữ liệu lớn

Làm thể nào để update vài triệu record ?

Tất nhiên mọi bài toán không thể chỉ dùng php là giải quyết được .

Ví dụ khi xây dựng một site kiểu này http://whois.cx/  . http://2name.com

Có khoảng 20 triệu domain cần cập nhật các thông số như : whois content .

Các site cần cập nhật định kỳ hoặc ngay lập tức (theo yêu cầu của người dùng) .

Mô hình hóa bài toàn với gearman như sau .

Cài đặt một gearman server . (Server sẽ đóng vài trò trung gian , phân phối thụ động các công việc)

Cài đặt các Worker (Công nhân ấy mà :D )

Các Worker cài đặt các hàm , ví dụ ở đây là hàm whois

Clone và chạy 1 loạt các worker giống nhau , trên các server , (mỗi server 20-30 worker) .

Mội khi cần update 1 domain (whois) thì client sẽ connect vào server và gửi yêu cầu whois .

Giống như chợ lao động , khi có một công việc , các công nhân anh nào nhanh tay nhận được công việc thì tiến hành làm ngay , rồi trả lại cho chủ (server - đốc công) rồi server trả lại cho client .

Dạo này khá bận nên không viết kỹ được .

Nhưng có thể tóm lược như sau :

- Gearman dùng hiệu quả hơn là dùng các giải pháp message queue thông thường , nếu dùng trên lamp .

- Nó đặc biệt hữu dụng khi dội dev chỉ thạo đúng php .

- Khi cần lập trình phân tán , job server , message queue ... hãy nghĩ đến Gearman .

Gearman là là giải pháp bao gồm Server , client , và worker .

Client yêu cầu công việc , các worker làm và server làm trung gian (Má mỳ).

Xem thêm tài liệu :

http://gearman.org/

http://www.slideshare.net/datacharmer/gearman-for-beginners

http://www.slideshare.net/felixdv/high-gear-php-with-gearman

http://highscalability.com/product-gearman-open-source-message-queuing-system

http://vi.wikipedia.org/wiki/Gearman

Thứ Bảy, 12 tháng 2, 2011

Cẩn thận khi sử dụng PHP fgetcsv

Trong quá trình xây dựng các ứng dụng, các lập trình viên thường ít quan tâm đến vấn đề import/export dữ liệu. Có lẽ là bởi đây là tính năng "giá trị gia tăng" và có thể "để mai tính".

Tuy nhiên, với khách hàng thì khác. Họ có thể sẽ đòi hỏi rất nhiều ở tính năng import/export này, theo các tiêu chuẩn khác nhau.

Tôi sẽ không tập chung vào các yêu cầu "nâng cao" mà khách hàng có thể nghĩ ra (ví dụ như định nghĩa các giá trị thay thế Yes->1, No->0, hay lấy các giá trị mặc định...). Tôi chỉ muốn tạo một vài chú ý khi sử dụng PHP fgetcsv cho việc import dữ liệu dưới định dạng csv.

Đây là một định dạng rất đơn giản nhưng thông dụng, nó có thể được soạn thảo bởi plaintext editor hoặc ứng dụng excel like.

Và tất nhiên sử dụng fgetcsv là giải pháp đầu tiên mà ta nghĩ tới. Tuy nhiên khi sử dụng fgetcsv cần phải lưu ý:

1. Encoding của import file tốt nhất nên là utf8. Nếu không bạn có thể gặp các lỗi mất mát các ký tự đặc biệt khi đọc với fgetcsv như là các ký tự điều khiển ASCII chẳng hạn. Nếu bạn phải hỗ trợ các encoding khác, tốt nhất là nên sử dụng các hàm stream_filter_* để tự động chuẩn hóa dữ liệu nhận được về dạng utf8. Làm như sau $fp sẽ luôn được đọc dưới dạng utf8 với fgetcsv:
<?php
class utf8encode_filter extends php_user_filter
{
function filter($in, $out, &$consumed, $closing)
{
while ($bucket = stream_bucket_make_writeable($in)) {
$bucket->data = utf8_encode($bucket->data);
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
$fp = @fopen($fileName, "r");
stream_filter_register("utf8encode", "utf8encode_filter")
or die("Failed to register filter");
stream_filter_prepend($fp, "utf8encode");
?>

2. Một tiện lợi và ... tiềm ẩn nhiều nguy cơ đó là việc fgetcsv hỗ trợ multiple lines data, có nghĩa là dữ liệu có thể nằm trên nhiều dòng. Nó phụ thuộc vào format của file csv. Và một sơ xuất nào đó (người soạn csv không dùng tools chuyên dụng mà lại xài notepad chẳng hạn. Bạn có thể thừa hoặc thiếu chỉ một dấu " thôi, thế là việc đọc csv sai bét cả. Tiềm tàng lớn nhất là việc ý đồ của bạn là mỗi record dữ liệu chỉ nằm trên một dòng. Nhưng sơ xuất khiến cho một record có một trường lấy toàn bộ các dòng tiếp theo trong file. Điều này dẫn đến việc chiều dài của dữ liệu nhận được lớn vượt quá giới hạn cho phép. Nếu file csv của bạn lớn, nó có thể sinh ra lỗi "trang trắng" (vì server từ chối xử lý tiếp vì một lý do nào đó liên quan đến dữ liệu của bạn).

Giải pháp toàn diện nhất cho việc này là sử dụng một csv validation cho file csv, trong đó quy định chiều dài tối đa của một trường dữ liệu cụ thể. Với php 5.3.x, chúng ta có thể đọc từng dòng của file và sử dụng str_getcsv cho dòng này (nếu ta luôn đảm bảo một record dữ liệu chỉ nằm trên một dòng csv).

-- Cập nhật với php 5.2.x tôi đã có một giải pháp như sau để luôn lấy dữ liệu trên một dòng --
<?php
$records = array();
$csv = fopen('test.csv', 'r');
$stream = fopen('php://memory', 'rw');
while(($data = fgets($csv) ) !== FALSE){
fwrite($stream, $data);
fseek($stream, 0);
$records[] = fgetscv($stream, 4096);
ftruncate($stream);
}

3. Với file dữ liệu lớn, sử dụng fgetcsv khá là chậm, với MySQL ta có giải pháp thay thế là LOAD DATA INFILE để đưa dữ liệu vào một bảng tạm. LOAD DATA INFILE có thể import 5M dữ liệu vào bảng tạm chỉ trong vòng 1 giây. Sau đó sẽ bỏ qua fgetcsv mà đơn giản là chỉ thao tác với các dữ liệu đã nhận được trong bảng tạm.

Thứ Sáu, 11 tháng 2, 2011

PHP addslashes có đủ tốt để chống SQL Injection?

Khi dạo qua các diễn đàn PHP, tôi thấy mọi người thường luận bàn về vấn đề này. Thực sự thì nó rất đơn giản.

1. PHP addslashes đủ tốt để chống SQL Injection  với các database sử dụng ' hoặc " để bao giá trị.

2. Nhưng addslashes chưa đủ tốt cho một cơ sở dữ liệu nào đó yêu cầu nhiều hơn việc thêm \ cho dấu ' và ". Ví dụ như đối với MySQL và đặc biệt khi xử lý các truy vấn với dữ liệu kiểu binary bắt buộc phải thêm \ cho \x00\n\r\'" and \x1a. Lúc này phải sử dụng hàm mysql_real_escapse_string.

Nên với MySQL, phải sử dụng mysql_real_escape_string trước khi gọi truy vấn thay vì sử dụng addslashes. Và với các database khác cũng vậy, phải tìm hiểu giải pháp có sẵn trong PHP trước khi dùng addslashes hoặc sáng tạo ra một hàm mới với mục đích tương tự (theo kiểu str_replace("'", "&apos;", $a) ). Hãy giả sử  database của bạn không dùng ' " để bao các dữ liệu thì sao :D, lúc đó mà dùng addslashes là tắt điện ngay.

Thứ Tư, 9 tháng 2, 2011

Sử dụng session_set_save_handler để override session handle

aViệc scale (vertical) ứng dụng web sử dụng php  , có một vấn đề cần quan tâm hàng đầu là vấn đề sử lý session .

Khi scale php sẽ chạy trên các máy chủ khác nhau , vậy làm thế nào để các user khi login web app mà dùng chung được session trên nhiều server ?

Để làm được điều này chúng ta cần xử lý sao cho tất cả các máy chủ đều sử dụng chung một hệ thống quản lý session .

Hoặc đơn giản là sử dụng chung một session storage .

Mặc định trong php sẽ sử dụng file session handle các file chứa session sẽ nằm trong /tmp của mỗi server .

Điều này có thể gợi ý cho chúng ta việc share chung 1 vùng lưu trữ (ví dụ dùng NFS để share chung /tmp giữa các máy chủ).

Tuy nhiên cách này lại ảnh hưởng đến tốc độ truy xuất (vì phải qua mạng - sau đó là đến việc máy host session sẽ quá tải diskio).

Một hướng khác là sử dụng một db mysql chung để lưu session , thực tế thì cách này tạm được .

Để làm như vậy chúng ta cần override lại các hàm xử lý session của php
session_set_save_handler("open", "close", "read", "write", "destroy", "gc");

Sử dụng hàm session_set_save_handler để trỏ các call back function cần thiết , như vậy chúng ta cần viết lại 6 hàm open, close , read ,write ,destroy , gc .

tạm thời chúng ta viết tạm các hàm như sau :
<?php
function open($save_path, $session_name)
{
echo "open";
}

function close()
{
echo "close";
}

function read($id)
{
echo "read";
}

function write($id, $sess_data)
{
echo "write";

}

function destroy($id)
{
echo "destroy";
}

function gc($maxlifetime)
{
echo "gc";
}

session_set_save_handler("open", "close", "read", "write", "destroy", "gc");
// test thử phát
session_start();

?>

Chạy thử . kết quả : openread writeclose ...

Như vậy chúng ta thấy thứ tự của một quá trình đọc session .

Việc tiếp theo là implement mấy hàm trên vào mysql , memcached , file , hay bất kỳ một storage nào có thể dùng chung được là xong .

với file (cái này chỉ là làm lại những gì php đã làm :D )
<?php
$sess_save_path=".";
function open($save_path, $session_name)
{
global $sess_save_path;

$sess_save_path = $save_path;
return(true);
}

function close()
{
return(true);
}

function read($id)
{
global $sess_save_path;

$sess_file = "$sess_save_path/sess_$id";
return (string) @file_get_contents($sess_file);
}

function write($id, $sess_data)
{
global $sess_save_path;

$sess_file = "$sess_save_path/sess_$id";
if ($fp = @fopen($sess_file, "w")) {
$return = fwrite($fp, $sess_data);
fclose($fp);
return $return;
} else {
return(false);
}

}

function destroy($id)
{
global $sess_save_path;

$sess_file = "$sess_save_path/sess_$id";
return(@unlink($sess_file));
}

function gc($maxlifetime)
{
global $sess_save_path;

foreach (glob("$sess_save_path/sess_*") as $filename) {
if (filemtime($filename) + $maxlifetime < time()) {
@unlink($filename);
}
}
return true;
}

session_set_save_handler("open", "close", "read", "write", "destroy", "gc");

//test
session_start();

?>

Hay với mysql đại khái thế này :
function read($id)
{
$sql = "select * from `tb_session` where `session_id`=$id";
mysql_query($sql);
//....
}

function write($id, $sess_data)
{
$sql = "INSERT INTO `tb_session` (`session_id`, `updated_on`) VALUES ('{$this->session_id}', NOW())";
mysql_query($sql);

}

function destroy($id)
{
$sql = "Delete from `tb_session` where `session_id`=$id";
mysql_query($sql);
}

Hay với memcached :
function read($id)
{
return memcached::get("sessions/{$id}");
}

function write($id, $data)
{
return memcached::set("sessions/{$id}", $data, 3600);
}

function destroy($id)
{
return memcached::delete("sessions/{$id}");
}

Dùng memcache hay mysql cũng khá nhanh , mysql thì chạy bàng memory storage engine , bật query cache tướng đối lớn cho nhanh , có thể replication ra nhiều server để đẩy performed lên cao nữa nếu tải lớn .

Thứ Ba, 8 tháng 2, 2011

Vài lệnh dùng trong việc theo dõi hệ thống linux

Thi thoảng con server nó lại đơ , có vài lệnh kiểm tra , khắc phục , sys admin nên biết vài lệnh này .

Lệnh top .

lệnh này đưa ra console các thông số cần quan tâm như : cpu load , load avg , memory , swap ..

Danh sách các active process
Tasks: 178 total,   1 running, 177 sleeping,   0 stopped,   0 zombie
Cpu(s):  2.1%us,  0.5%sy,  0.0%ni, 97.4%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   3352300k total,  1400284k used,  1952016k free,   135704k buffers
Swap:  2178044k total,        0k used,  2178044k free,   659304k cached

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
2181 ngocbd    20   0  571m 192m  30m S    3  5.9  15:49.59 firefox-bin
2215 ngocbd    20   0  190m  60m  18m S    1  1.8   7:47.10 plugin-containe
1003 root      20   0 89528  36m  13m S    1  1.1   6:13.07 Xorg
3519 ngocbd    20   0  2620 1148  840 R    1  0.0   0:00.03 top
1800 ngocbd    20   0 31320 8772 7100 S    0  0.3   0:05.79 multiload-apple
2117 ngocbd    20   0 43192  20m 4760 S    0  0.6   0:10.16 ubuntuone-syncd
2449 ngocbd    20   0 94040  14m  10m S    0  0.5   0:07.87 gnome-terminal
1 root      20   0  2888 1772 1244 S    0  0.1   0:00.47 init
2 root      20   0     0    0    0 S    0  0.0   0:00.00 kthreadd
3 root      20   0     0    0    0 S    0  0.0   0:00.08 ksoftirqd/0
4 root      RT   0     0    0    0 S    0  0.0   0:00.00 migration/0
5 root      RT   0     0    0    0 S    0  0.0   0:00.00 watchdog/0
6 root      RT   0     0    0    0 S    0  0.0   0:00.00 migration/1
7 root      20   0     0    0    0 S    0  0.0   0:00.11 ksoftirqd/1
8 root      RT   0     0    0    0 S    0  0.0   0:00.00 watchdog/1

Nguyên về cái lệnh này cung khá phức tạp .

Đang trong màn hình top cũng có vài lệnh .

Bình thường 1s (1 giây) top sẽ cập nhật lại thông số 1 lần . Nhưng nếu bạn cần nó cập nhật luôn và ngay ấn a

Chả biết ấn cái gì thì ấn h (help ấy mà) . Còn nhiều thứ nữa các bạn xem trong help của nó luôn nhé .

Lệnh free

Xem dung lượng memory còn trống .

free -m (qui đổi ra MB dễ nhìn nhất)

free -g (qui đổi ra GB)

Các vùng nhớ cached nhìn chung là vẫn alloc được

free -c số_giây_cập_nhật cho sướng mắt

Lệnh sar ( lệnh này có thể không đi kèm cùng os , trên ubuntu cài bàng lệnh sudo apt-get install sysstat)

Để xem thông số 3 giờ trược (cập nhất 10 phút/lân)

sar 4 5 để xem thông số trực tiếp (live) 4 lần , cập nhật 5s/lần

Lệnh iostat

Để xem thông tin truy xuất vào ổ cứng .

Lệnh pstree

Đển xem process tree , xem process được tạo ra bởi process cha nào ..

lệnh w

Để xem ai login vào hệ thống

Lệnh ps

Lệnh này phức tạp nhất ,

ps -A để xem danh sách các process

ps au để xem thêm tên user và command

thường thì dùng ps aux rồi grep cái mình quan tâm

pkill , kill , killall

để kill các process nếu thấy nó ngứa mắt .

Trên win thì có tasklist và taskill dùng cũng thế .