Thứ Ba, 20 tháng 12, 2011

Cài đặt resin webserver trên centos

Resin là webserver/servlet container rất mạnh . Có thể nó là nhanh nhất , với cở 10k  concurrent connection  .

1. Cài jdk (tốt nhất là jdk7)

http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.rpm
wget http://download.oracle.com/otn-pub/java/jdk/7u2-b13/jdk-7u2-linux-x64.rpm

rpm -i jdk-7u2-linux-x64.rpm

2.Cài resin
wget http://www.caucho.com/download/resin-4.0.24.tar.gz

tar xzf resin-4.0.24.tar.gz

start thử :

cd resin-4.0.24

sh bin/resin.sh start

3.Cài thành service
cd resin-4.0.24

./configure

make

make install

Chú ý tại bước này có thể script configure sẽ không làm việc vì đoạn code sau
tmpname="/tmp/java$$.out"

$JAVA_EXE -version 2> $tmpname

grep "1\.[678]" $tmpname 1> /dev/null
if test "$?" != "0"; then
echo "no"
java_version=`cat $tmpname`
as_fn_error $? "Java 1.6 required. ${JAVA_EXE} returned: ${java_version}" "$L
NENO" 5

Đoạn code này sẽ check xem vesion của java có phải là 1.6[7,8] hay không . Nhưng cái java version thì lại là 1.6.0_23 hay 1.7.0

Vì vậy có thể code lại đoạn trên grep "1\.[678]" sửa thành grep "1\.[678]\.[0-9]\"

Xong bước này là bạn đã có thể chạy resin service

service resin restart

Các công việc cần làm tiếp theo : config admin username/password

config virtual host

config memory/heap

Thứ Ba, 1 tháng 11, 2011

Làm việc với mongodb trong java

Để  làm việc được với mongodb trước hết bạn download thư viện mongo tại link sau : http://www.mongodb.org/downloads

Cũng như bất kỳ loại CSDL nào để làm việc được trước hết bạn cần kết nối với CSDL của mongodb :

Mongo m = new Mongo("localhost"); //connect tới server mongo trên local,nếu bạn đặt mongo trên một server khác ,bạn cũng có thể kết nối tới bằng cách thay localhost = tên server mà bạn đặt mongo.Điểm hay của mongo là bạn có thể đặt code và CSDL của bạn ở 2 server hoàn toàn khác nhau -> điều này giúp cho việc dùng chung CSDL một cách hết sức thuận tiện

DB db = m.getDB("demomongo"); // connect tới database demomongo

DBCollection coll = db.getCollection("demo"); // connect tới bảng demo

Ok,vậy là việc kết nối với mongodb đã hoàn tất,giờ tới việc insert và select cũng hét sức đơn giản,thư viện mongodb cung cấp cho bạn các hàm để có thể thao tác với mongodb một cách thuận tiện .

Để insert một record và bảng demo ta làm như sau :
        BasicDBObject doc = new BasicDBObject(); // khái báo một đối tượng BasicDBObject 

doc.put("name", "MongoDB"); //put dữ liệu và đối tượng vừa tạo ra
doc.put("type", "database");
doc.put("count", 1);

coll.insert(doc); //insert vào bảng

Để select ra 1 phần tử :
          DBObject myDoc = coll.findOne();
System.out.println(myDoc);

Select ra nhiều phần tử :
DBCursor list = coll.find(new BasicDBObject("name","MongoDB")); // tim tất cả những record có name="MongoDB"

Để update 1 record :

DBObject myDoc = coll.findOne();


myDoc.put("update","true");

coll.save(mydoc); //up date đối tượng myDoc

Chủ Nhật, 28 tháng 8, 2011

JoomFish and VirtueMart

Sử dụng JoomFish và VirtueMart để làm website bán hàng đa ngôn ngữ :

Ở đây mình dùng Joomla 1.5.22 – JoomFish 2.1.7 – VirtueMart 1.1.9

B1 : Cài JoomFish

B2 : Cài VirtueMart

B3 : Cài đặt gói ngôn ngữ bạn muốn sử dụng (ở đây mình cài gói ngôn ngữ là tiếng việt)

B4 : Sau khi đã cài đặt gói ngôn ngữ, bạn vào joomfish và active cho nó :

Components >>> Joom!Fish >>> Content Languages

joomfish-active language

B5 : Vào phpMyAdmin , chọn database bạn đang dùng, gõ lệnh sau :

ALTER TABLE `jos_vm_product_attribute_sku` ADD `attribute_sku_id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST ;

joomfish-active language

B6 : Download VM_Ce.zip, giải nén, copy paste vào thư mục :

your_root_folder/administrator/components/com_joomfish/contentelements

B7 : Download file shop_browse_queries.zip giải nén , copy rồi paste đè lên file cũ :

your_root_folder/administrator/components/com_virtuemart/html

Vậy là xong, bây giờ vào joom!Fish , chọn content element rồi dịch thôi.

Components >>> Joom!Fish >>> Translation

Joomfish-translate

Thứ Bảy, 6 tháng 8, 2011

Sử dụng layout trong CakePHP

Khi sử dụng Framework để lập trình , có rất nhiều vấn đề mà người lập trình viên cần phải quan tâm . Trong đó có phần xử lý dao diện là một phần không thể thiếu . Trong bài viết này , mình sẽ hướng dẫn các bạn làm sao sử dụng layout trong CakePHP Khi ta viết một ứng dụng cho CakePHP . mặc định CakePHP đã hổ trợ cho chúng ta dao diện sẵn . Nhưng đôi khi tùy theo sở thích, nhu cầu , xu hướng … nên bắt buộc người thiết kế cũng như người lập trình cần có những giao diện (layout) cho riêng mình. Bài viết sẽ hướng dẫn cách chúng ta tạo 1 layout cho riêng mình và cách áp dụng 1 Helper CakePHP vào ứng dụng của mình. Khi phân tích 1 trang web , nhìn chung ta thấy gồm các phần chính như sau : null


Để vận dụng được sự hổ trợ mạnh mẽ chắc năng load layout của FrameWork CakePHP , ta phân tích các thành phần cố định và thành phần động : null


Như vậy ta để tránh việc xử lý các thành phần cố định ở controller ta chỉ cần viết 1 class Hepler để hiển thị nó . Còn thành phần động sẽ được xử lý thông qua Controllers. Cái file cần chuẩn bị trong Tutorial Layout CakePHP như sau :


 app/controllers/templates/ : -templates_controller.php (Controller chính để load layout)


 app/views/templates/ :


- index.ctp


- view.ctp


app/views/helpers/ :


- common.php (Tạo các thành phần cố định : menu , header,footer)


 app/views/layouts/ :


- template.ctp (File chứa nội dung layout)


 app/webroot/css/ :


- style.css (file CSS của layout)



Tạo file common.php (app/views/helpers/)


[php]


<?php
class CommonHelper extends HtmlHelper {


// Hàm tạo menu
function create_menu(){
$menu  = "<ul>";
$menu .= "<li>".$this->link("CodeIgniter",array("controller"=>"templates","action"=>"view",1))."</li>";
$menu .= "<li>".$this->link("CakePHP",array("controller"=>"templates","action"=>"view",2))."</li>";
$menu .= "<li>".$this->link("Zend",array("controller"=>"templates","action"=>"view",3))."</li>";
$menu .= "</ul>";
return $menu;
}

[/php]

//Hàm tạo các thành phần cho header và footer
function general(){
$data = array(
"header" => "QHOnline.info",
"footer" => "Copyright 2011 © | QHTeam",
);
return $data;
}
?>


Tạo file templates_controller.php (app/controllers/templates/) :


<?php
class TemplatesController extends AppController {
var $layout = "template"; // load file chứa nội dung layout : views/layouts/template.ctp
var $helpers = array("Html","Common"); // Thành phần Helper Common được gọi để tạo menu,header,footer trong view


function  index(){
$this->set('title_for_layout', 'Templates By QHOTeam');
$this->set("content","QHO Team");
}

function view($id){
switch($id){
case 1 :{
$this->set('title_for_layout', 'CodeIgniter FrameWork');
$this->set("content","CodeIgniter FrameWork");
}
break;
case 2 :{
$this->set('title_for_layout', 'CakePHP FrameWork');
$this->set("content","CakePHP FrameWork");
}
break;
case 3 :{
$this->set('title_for_layout', 'Zend Framework');
$this->set("content","Zend Framework");
}
break;
default :
$this->set("content","Framwork");
break;
}
}

}
?>


Tạo file layout template.ctp (app/views/layouts/template.ctp) : File này chứa nội dung layout bao gồm các thành phần cố định và thành phần động như ban đầu mô tả. Nội dung file này gồm mã HTML và PHP…


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?php echo $title_for_layout;?></title>
<?php echo $this->Html->css("style"); // link oi file style.css (app/webroot/css/style.css)?>
<?php $general = $this->Common->general(); // Lấy các giá trị của thành phần tĩnh : header,footer ?>
</head>
<body>
<div id="top">
<center><h2><?php echo $general['header']; ?></h2></center>
</div>
<div id="main">
<div id="menu">
<?php echo $this->Common->create_menu(); // goi ham tao menu tu common helper?>
</div>
<div id="content">
<h1><?php echo $content; // Thành phần động ?></h1>
</div>
</div>
<div id="footer">
<center><?php echo $general['footer'];?></center>
</div>


</body>
</html>


Tạo file style.css (app/webroot/css/style.css)



Hình mô ta khi file template.ctp sử dụng file helper Common.phpbody {
margin: auto;
width: 1000px;
font-family: Verdana, Geneva, sans-serif;
}
#top {
float: left;
width: 1000px;
height: 100px;
background-color: #F36;
color: #FFF;
}
#main {
float: left;
width: 1000px;
}
#menu {
float: left;
width: 200px;
background-color: #F96;
}
#menu ul {
margin: 0px;
}
#menu a {
color: #FFF;
font-size: 12px;
}
 

#content {
float: left;
width: 800px;
}
#content h1 {
font-size: 18px;
color: #0CF;
padding-left: 50px;
}

#footer {
float: left;
width: 1000px;
height: 50px;
background-color: #96C;
font-size: 12px;
font-weight: bold;
color: #FFF;
}

Hình mô ta khi file template.ctp sử dụng file helper Common.php
null

Như thường lệ , khi tạo 1 fuction cho 1 Controller , thì ta phải tạo file view tương ứng để hiển thị nội dung trong file view đó.Trong ví dụ này ta có Controller Templates với 2 function là index() và view(), cần phải có 2 file view là : index.ctp và view.ctp để hiển thị nội dung tương ứng.

Tuy nhiên chúng ta đang sử dụng layout template.ctp (app/views/layouts/template.ctp) ,nên chỉ cần tạo 2 file index.ctp và view.ctp ,nội dung của 2 file này các bạn bỏ trống. Ví dụ function index() được gọi , nó sẽ load file index.ctp và tự động nạp file layout vào (app/views/layouts/templates.ctp).

Hình mô tả khi file view load file template.ctp

null

Chạy thử ứng dụng :
http://localhost/cakephp/templates
null
null
Khi click vào link của Menu : http://localhost/cakephp/templates/view/1
null

Thứ Tư, 3 tháng 8, 2011

CouchDB cơ bản cho lập trình viên PHP

Là lập trình viên PHP thì chắc hẳn mình đã quá quen thuộc với việc tương tác cơ sở dữ liệu (CSDL), dám cá là phần nhiều trong số các bạn đọc bài này dùng MySQL cho công việc/học tập hàng ngày :)

Thực tế chứng minh MySQL là lựa chọn tốt cho dữ liệu có cấu trúc[1] và nhiều ràng buộc[2]. Mình bắt đầu bằng thiết kế các schema, tạo các bảng, định nghĩa kiểu dữ liệu cho các cột và tiếp theo là viết code cho các thao tác CRUD[3]. Vấn đề là trong dự án sẽ có nhiều trường hợp dữ liệu không đoán trước được kiểu, định dạng, độ lớn, hay các đặc tính cần có. Nếu mình thiết kế schema để đón đầu, CSDL sẽ theo thời gian chứa nhiều field bị null, hoặc phát sinh các ràng buộc phức tạp, câu lệnh SQL cũng vì thế mà rắc rối lên nhiều.

Với dự án như này, hãy thử một hướng đi khác, ko liên quan đến CSDL quan hệ. Vậy cái mình cần là 1 CSDL dạng document-based, schema free, ad-hoc.

Question: Với một Web developer thì tại sao lại phải biết SQL để lập trình web (?).

CouchDB là gì?

Theo Apache CouchDB website, CouchDB là

  • document database server, truy vấn thông qua RESTful JSON API[3].

  • ad-hoc, flat, và schema-free[4].

  • distributed.

  • sử dụng Javascript để query dữ liệu.


Cấu tạo một CouchDB như sau

- database

- document

+ _id

+ _rev

+ {"field" : "value"}

+ {"field" : "value"}

...

Ví dụ

- database: contacts



{

_id: 528c3917ed78a2ce16ddc130f700063f

_rev: 1-901de5ccbf8ff7faf4ad09475939f160

fullname: "Black Jack"

occupation: "IT"

skills: ["web", "desktop", "ajax", "php", "javascript","HTML"]

}



Trong document trên, _id là UUID[5], _rev là phiên bản tài liệu, 3 trường chứa giá trị là fullname, occupation, skills thể hiện dạng JSON.

Việc truy vấn dữ liệu được thực hiện thông qua các phương thức RESTful JSON API. Trên thực tế, nếu mình biết về Javascript, Ajax, JSON thì mình không cần phải biết về SQL để làm website(!)

Cài đặt CouchDB

Trên Ubuntu thì
sudo apt-get install couchDB
sudo /etc/init.d/couchdb start

Vậy là xong thôi. Service couchDB được chạy mặc định ở cổng 5984. Từ trình duyệt, gõ http://127.0.0.1:5984 mình sẽ thấy đại loại như
{"couchdb":"Welcome","version":"1.0.2"}

Tiếp theo, chạy trình quản lý Futon được tích hợp vào CouchDB, nó giống như PhpMyAdmin

http://localhost:5984/_utils/


Bước tiếp theo sẽ là thực sự xài CouchDB

Sử dụng CouchDB API

Tại thời điểm này, mình sử dụng cURL[6] để gửi các phương thức GET, PUT, POST, DELETE thông qua HTTP tới CouchDB

Câu lệnh đầu tiên

curl http://127.0.0.1:5984/

Kết quả:
{"couchdb":"Welcome","version":"1.0.2"}

Tạo CSDL mới
curl -X PUT http://127.0.0.1:5984/contacts

Khi bạn nhận được thông tin {"ok":true}, CSDL contacts đã được tạo

Lấy về tất cả cơ sở dữ liệu

curl -X GET http://127.0.0.1:5984/_all_dbs

Tạo 1 record mới trong contacts
curl -X PUT http://127.0.0.1:5984/contacts/*id* -d '{ *json_data* }'

ví dụ:
curl -X PUT http://127.0.0.1:5984/contacts/contact1 -d '{ "fullname":"Doraemon",
"type":"cat" }'

Lấy thông tin về record vừa tạo
curl -X GET http://127.0.0.1:5984/contacts/contact1

Cái đáng phải quan tâm là, với việc gửi đi các phương thức khác nhau, CouchDB sẽ thực thi các hành động khác nhau. Trong ví dụ trên, GET là lấy về, PUT là tạo mới. Bên cạnh đó, CouchDB không phải là object oriented database[7] nên tránh dùng persistent data layer[8].

---

Đón xem phần 2: hoàn thiện phần 1 và giới thiệu cách kết hợp PHP & CouchDB

Thứ Sáu, 8 tháng 7, 2011

Giảm độ lớn của INDEX trong MySQL

Hi All,

Trong quá trình tìm giải pháp cho vấn đề của mình, bắt được một bài viết khá hay ở đây:

http://kevin.vanzonneveld.net/techblog/article/create_short_ids_with_php_like_youtube_or_tinyurl

Đây là bài viết nói về cách làm giảm chiều dài của ID trên URL (giống như của YouTube).

Tuy cái này hay, nhưng chưa giúp mình trong việc giải quyết vấn đề sau đây.

Mình có một CSDL các sản phẩm (khoảng 1 tỉ). Khi INSERT một sản phẩm mới, mình muốn kiểm tra xem tên sản phẩm này có trong CSDL hay chưa.

Nếu sử dụng Zend Lucene hoặc MySQL Index thì dung lượng index khá là lớn. Vì vậy mình muốn HASH các tên sản phẩm vào một trường khác với chiều dài nhỏ hơn.

Khi so sánh tên sản phẩm thì sử dụng HASH CODE này.

Giải pháp của mình là sử dụng mã md5 raw, với chiều dài là 16 bytes. Với 1 tỉ records thì nó ngốn xấp xỉ 15 GB.

Mình chấp nhận khả năng trùng lặp ở một số trường hợp.

Tuy nhiên mình muốn giảm chiều dài của HASH CODE xuống nữa thì nên sử dụng biện pháp gì.  Mình chấp nhận khả năng bị trùng lặp nhiều hơn (tức là có 2 sản phẩm khác tên nhưng hashcode có thể vẫn giống nhau)?

Bởi vì mình nghĩ có 1 tỉ item, vẫn chỉ là INT(11) = 4 bytes, xài 16 bytes thì ... thấy hơi phí. Nếu có giải pháp giúp mình giảm xuống 8 bytes thì tốt nhất :D

Thứ Năm, 30 tháng 6, 2011

HTML5 đã hoàn thiện ở mức độ nào?

http://slides.html5rocks.com

Lang thang trên mạng tìm hiểu về làm game thì em thấy cái này.

Em xin được chỉ giáo về HTML5. Em muốn biết HTML5 đã hoàn thiện ở mức độ nào rùi (nhất là tính tương thích trình duyệt). Em cũng đã có tìm hiều qua, nói chung vẫn mỗi trình duyệt một phách, khó xử quá.

Ngoài ra em muốn học hỏi một chút về làm game (chạy bằng trình duyệt chứ không phải app) trên mobile thì cần chú ý những điểm gì không. Chủ yếu là Andoid và Iphone. Em cũng xin được list ra những băn khoăn của em cho vấn đề này luôn:

1) Lựa chọn công nghệ: Flash, Silverlight, HTML5 cái nào?

2) Những sự khác biệt giữa mobile browser & desktop browser

3) Có nên làm game theo kiểu vector rùi resize tùy màn hình (cái này có thể áp dụng nếu trả lời của câu 2) là không khác nhau là mấy), hay là nên làm game nhiều bản phục vụ các loại user agent khác nhau.

Thứ Sáu, 24 tháng 6, 2011

Build Check Google PageRank app with Prapi API

Hôm vừa rồi tớ có code demo cai' app để check free Google Pagerank.

Giới thiệu về app này nhé :

Check Google Pagerank  là một app free dùng để check Google Pagerank cho website của bạn. Trong app này, tớ có sử dụng sẵn api của Prapi để có thể lấy về và show ra google pagerank một cách dễ dàng ^^

Cả nhà có thể down app tại đây

Còn source code ở đây

PS: trong source code đã comment đầy đủ

Thứ Năm, 9 tháng 6, 2011

Mongo DB free với mongohq.com

mongohq.com miễn phí một online mongo db max 16M .
Đủ để làm thử nghiệm các ứng dụng .

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

Một số thuật ngữ hay chém

Chào bà con,

Hôm nay lang thang tự dưng thấy mấy từ viết tắt như này: OOP, ORM, RAD, DRY, KISS, TDD, YAML, PEAR

Ai diễn đạt tốt (trừ đại ka) thì giải thích ý nghĩa kèm minh họa mấy cái trên phát, ổn thì tớ bao chơi điện tử 1 buổi :D

Thứ Sáu, 20 tháng 5, 2011

Cài đặt opencv trên ubuntu

Cài đặt opencv trên ubuntu thật sự rất đơn giản .
Các bước :

1.sudo apt-get install build-essential

Thường thì build-essential đã được cài .
2.sudo apt-get install libavformat-dev
Cũng có thể đã được cài
3.sudo apt-get install ffmpeg
Cũng không cần thiết lắm nhưng nên cài
4.sudo apt-get install libcv2.1 libcvaux2.1 libhighgui2.1 python-opencv opencv-doc libcv-dev libcvaux-dev libhighgui-dev

Lib cho python cài hay không cũng được

Sau khi cài đặt thành công . Bạn có thể mày mò example .
Tốt nhất là copy example về home (~) cho tiện
cd ~
cp -r /usr/share/doc/opencv-doc/examples .
cd c
cd c
./build_all.sh
Để build hết các example
Chạy thử :
./morphology

Bạn có thể học bàng cách giải nén các example khác trong thu mục này . Edit code , thay file ảnh , rồi build lại ...

Thứ Sáu, 13 tháng 5, 2011

Mẹo mực với Eclipse PDT

Khi làm việc với Eclipse PDT, đôi khi bạn gặp phải những tình huống như:

1/ Mất chức năng AutoComplete?

Đơn giản là hãy xóa file .project đi và refresh lại. Lỗi này thường gặp khi bạn Create Project from SVN

2/ Khi làm việc với những đối tượng như CakePHP, giả sử với AuthComponent bạn muốn gọi trong Controller như sau: $this->Auth->something, nếu có AutoComplete cho cái something kia thì tốt hơn đúng không ạ.

Những lúc thế này mình phải khai báo biến Auth cho controller mình đang sử dụng:

/**
* @var AuthComponent
*
* @var Auth
*/
var $Auth;

3/ Với template thì sao, template thì ná ná giống functional based code. Do đó mẹo như sau:

Đưa file này https://github.com/markstory/story-scribbles/blob/master/eclipse/code-completion-in-views.php vào bất cứ thư mục nào (trừ thư mục gốc của project). Bạn sẽ có AutoComplete cho form.

4/ Về Code AutoComplete cho CakePHP em đã tham khảo ở đây:

http://mark-story.com/posts/view/code-completion-for-cakephp-in-eclipse

Thứ Năm, 12 tháng 5, 2011

Angry Birds gets a web version

Phiên bản HTML5 của game Angry Birds, chơi ngay trên trình duyệt .

check it out : http://chrome.angrybirds.com

plan and zombie : http://chrome.plantsvszombies.com/

Google music free

Hàng mới trong google IO day 1 . http://music.google.com/about/
US only và free nhé . Dùng proxy hoặc sock đề vào

Content in the cloud:

  • Currently: apps and books

  • New: Google Music Beta. [4]

    • Upload via app (on Windows and Mac)

    • Up to 20,000 songs.

    • Free while in beta.

    • Play music via web or Android app.

    • Offline: automatic caching of recently played music. Manually mark artists, albums, or playlists, for offline use.



  • New: movies, including rentals. They can be “pinned” (cached) for offline use.

Thứ Sáu, 6 tháng 5, 2011

HTTPs có dấu cả request path không?

Chào các bác,

Em có một liên kết như sau: https://domain.com/private/75415d70-79e3-11e0-819a-0800200c9a66

Em muốn hỏi là request này có mã hóa cái đoạn /private/75415d70-79e3-11e0-819a-0800200c9a66 trước khi chuyển đi không?

Sau mấy ngày tìm hiểu hỏi han khắp nơi. Em nhận được câu trả lời là có.

Thứ Tư, 27 tháng 4, 2011

Task Queues with google app engine

Thông thường với việc thực hiện crawler các trang web khác thì tại một thời điểm bạn chỉ có thể thực hiện một request đến trang craw,muốn tại một thời điểm gọi được nhiều request thì tương ứng bạn phải nhân lượng craw tại một thời điểm lên,công việc này thực sự không đem lại hiểu quả.Với task queues thì công việc này trở lên hết sức đơn giản,chỉ cần thực hiện một crawler bạn có thể thực hiện nhiều request tới url.Có thể hiểu một các đơn giản là task queues giúp bạn thực hiện các công việc được phân công một cách đồng thời.

Trước hết tạo file queue.xml trong WEB-INF có nội dung

<queue-entries>
<!--Change the refresh rate of the default queue to 1/s-->
<queue>
<name>default</name>  //ten tash queue se được gọi trong servlet
<rate>100/s</rate>  //số lầ thực hiện task queues trong 1s
</queue>
</queue-entries>

tạo một servlet để add các task queues.(DemoServlet.java)

package Showsiteinfo.cron;

import java.io.IOException;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions.Method;

import static com.google.appengine.api.taskqueue.TaskOptions.Builder.*;

@SuppressWarnings("serial")

public class DemoServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");

for(int i=0;i<100;i++)
{
Queue queue = QueueFactory.getDefaultQueue();  //goi defaulse task queues được config trong file queue.xml
queue.add(withUrl("/queue").method(Method.GET).param("name", "abc"));  // goi url queue sử dụng phương thức get vói parameter name=abc
}
}

}

Vào web.xml chỉnh đường dẫn tới DemoServlet.java là /demo

Giờ nhiệm vụ của chúng ta là chay link /demo,như vậy sau 1s (có thể trễ 1 chút) chúng ta đã thực hiện được 100 request tới url /queue.

Hạn chế của google là không cho chúng ta gọi link từ domain hay một app khác mà chỉ có thể thực hiện trong chính app ma bạn đang thực hiện task queues.

HANOI MOBILE DAY 201

MOBILE DAY 2011 (14/5/2011)
Nếu bạn có ý định chia sẻ kiến thức & kinh nghiệm liên quan tới Mobile cho cộng đồng!

MODILE DAY 2011
Sự kiện về Mobile tại Việt Nam.
Khoảng 500 người tham gia.
Số lượng diễn giả & topic: 12 topics chỉ nói về Mobile.
Số phòng hội thảo đồng thời: 2
Chi phí tham gia: miễn phí

ĐĂNG KÝ TOPIC & DANH SÁCH TOPIC
Bạn có thể trực tiếp thêm topic vào danh sách.
Ngày 05/05 danh sách sẽ được khóa.
https://spreadsheets.google.com/spreadsheet/ccc?key=t14PDT_pmPuAbUpmPAHeq5g&authkey=CNfcg7kH#gid=1

TOPIC
Đây là một số topic gợi ý, bạn có thể chọn bất kỳ topic nào.

Lập trình trên iPhone, Android
Lập trình trên Windows Phone, Bada, Symbian
Thị trường Mobile Việt Nam & Thế giới
Mô hình kinh doanh trên Mobile
Đặc trưng của mạng xã hội trên Mobile
User Experience & Thiết kế đồ họa trên Mobile

Chú ý là: thị trường Mobile còn rất trẻ, 80% người tham gia là junior, do đó nói các topic càng đơn giản dễ hiểu thì càng thu hút nhiều người quan tâm.

BẠN ĐƯỢC GÌ?
- Cơ hội chia sẻ cho cộng đồng
- Sự kính trọng & biến ơn từ cộng đồng
- Thử nói chuyện trước 100 ~ 200 người

BẠN MẤT GÌ?
- Thời gian
- Không có thù lao

BẠN CẦN CHUẨN BỊ GÌ?
- Thông tin tự giới thiệu về bạn, gửi sớm cho BTC để đưa lên website, để PR từ sớm.
- Nhớ gửi một / một vài bức ảnh của bạn, thật đẹp, cũng để đưa lên website

LƯU Ý
- Có một phòng VIP dành riêng cho BTC và diễn giả, khá đẹp.
- Đây là biệt khu, bạn có thể vào đó để chuẩn bị hoặc nghỉ ngơi.
- Buổi trưa BTC sẽ lo vụ ăn uống ngay trong phòng VIP

CHỖ ĂN NGHỈ?
- Bạn có thể nghỉ tại khách sạn Kim Liên (ngay bên cạnh khu hội thảo)
Số 7, Dao Duy Anh Str., Dong Da District, Ha Noi
Tel. 84.4.38522522; 25770328 Fax. 84.4. 35770463

Thứ Bảy, 23 tháng 4, 2011

Sinh mã số theo dải quy định trước

Như đã nói trong comment trước. Em sẽ trình bày một phương pháp sử dụng trường autoincrement để sinh mã số theo dải số quy định trước.

Như các bác thấy, trong thực tế, có rất nhiều trường hợp gặp phải ví dụ như là, mỗi một thành phố có một dải số chứng minh thư riêng chẳng hạn, hoặc trong một nhà máy, ID của mỗi sản phẩm họ quy định một dải số riêng như kem đánh răng thì từ 10000 đến 20000, còn bàn chải thì từ 20001 đến 30000...

Vậy thì làm thế nào? Cách đơn giản mà ta có thể nghĩ ra ngay là sử dụng một cơ chế khóa để luôn đảm bảo quá trình sinh mã được thực hiện theo thứ tự lần lượt. Em sẽ không comment gì cách này nữa.

Cách của em muốn đề cập ở đây là sử dụng một bảng như sau:

CREATE TABLE `seq` (
`CODE` varchar(255) NOT NULL,
`AUTO` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`CODE`),

UNIQUE KEY `CODE` (`CODE`,`AUTO`)

) ENGINE=MyISAM  DEFAULT CHARSET=latin1


Sau đó định nghĩa giá trị ban đầu của dải KEMDANHRANG là 9999 và dải BANCHAI là 20000

INSERT INTO `seq` (`CODE`, `AUTO`) VALUES ('KEMDANHRANG', '9999');
INSERT INTO `seq` (`CODE`, `AUTO`) VALUES ('BANCHAI', '20000');


Sau đó, nếu bạn muốn tính toán mã tiếp theo của bàn chải chẳng hạn, bạn sử dụng query sau:

replace into seq (`CODE`,`AUTO` ) values ('BANCHAI', '')

Lúc này, giá trị trả về của mysql_insert_id sẽ là auto number tiếp theo của bàn chải (là 20001).

Tương tự như vậy:

replace into seq (`CODE`,`AUTO` ) values ('KEMDANHRANG', '')

Sau truy vấn này, mysql_insert_id trả về 10000 (auto number của dải kem dánh răng).

Tất nhiên để kiểm soát giá trị trên của dài. Sau khi lấy được mã, chúng ta phải tự so sánh giá trị lấy được với giá trị trên để xem mã vừa lấy được có phù hợp hay không.

Thứ Năm, 21 tháng 4, 2011

Cài đặt gnome 3 trên ubuntu 10.10

Cách này cài gnome 3 thông qua gnome-shell

1.Cài mấy thư viện để build

sudo apt-get install curl libtiff4-dev libgstreamer0.10-dev libcroco3-dev xulrunner-dev mesa-utils mesa-common-dev libreadline5-dev libgl1-mesa-dev libwnck-dev librsvg2-dev libgnome-desktop-dev libgnome-menu-dev libffi-dev libgtk2.0-dev libgconf2-dev libdbus-glib-1-dev gtk-doc-tools gnome-common git-core flex bison automake build-essential icon-naming-utils autopoint libvorbis-dev libpam-dev libgcrypt-dev libtasn1-dev libtasn1-3-bin libgnome-keyring-dev libupower-glib-dev libxklavier16 libxklavier-dev xserver-xephyr python-dev libpulse-dev libjasper-dev jhbuild libgtop2-dev libsqlite3-dev libproxy-dev libdb-dev libproxy-dev libcups2-dev libusb-1.0-0-dev

2.Download build script

wget http://git.gnome.org/browse/gnome-shell/plain/tools/build/gnome-shell-build-setup.sh

3.Chạy build script

chmod +x gnome-shell-build-setup.sh
./gnome-shell-build-setup.sh


4.build

jhbuild build

Quá trình build có thể một số gói sẽ không cài được . Trong trùng hợp này hãy chọn option 2 để tiếp tục cài đặt


*** Installing gnome-power-manager *** [39/41]
make install
make: *** No rule to make target `install'. Stop.
*** Error during phase install of gnome-power-manager: ########## Error running make install *** [39/41]


[1] Rerun phase install
[2] Ignore error and continue to next module
[3] Give up on module
[4] Start shell
[5] Reload configuration
choice: 2

5. Dùng thử .

gnome-shell –-replace

6.Thình thoảng bạn build lại để cập nhật code mới từ gnome-git

Quyên show hàng http://i-php.net/Screenshot.png

Chủ Nhật, 17 tháng 4, 2011

Tại sao tôi lại được khuyến cáo không sử dụng TRIGGER và PROCEDURE của MySQL?

Chào các bác,

Em mới vào Sài Gòn chưa được ít lâu. Hiện đang đi phỏng vấn xin việc. Được mấy công ty rồi, ở trong này cách họ truy vấn lúc phỏng vấn khá là khác biệt so với các công ty em đã làm ở ngoài Hà Nội. Đại khái em thấy họ tập chung vào các kinh nghiệm làm việc thực tế, hơn là lý thuyết chung chung. Đặc biệt là họ chỉ focus vào các yêu cầu của công việc, chẳng đoái hoài gì đến giá trị gia tăng gì sất (cũng hơi là lạ lúc đầu nhưng sau 3 lần phỏng vấn em cũng thấy quen rồi và cũng cho thế là hợp lý, tuyển PHP, MySQL thì sức đâu mà lo đến Java, Python... khác). Khi xin tuyển công ty khác thì em cũng sửa sửa, xóa xóa tùy theo yêu cầu tuyển dụng :D.
À quay lại chủ đề chính. Có một công ty em tuyển có trao đổi một đoạn như sau (với anh xếp Việt Kiều Úc, công ty KiSS Concept):

...

- Em đã  bao giờ sử dụng tính năng như TRIGGER, PROCEDURE trên các dự án của mình chưa?

- Chưa. Em được khuyến cáo là không sử dụng những tính năng đó của MySQL. Thay vì thế, dùng mã PHP.

- Tại sao vậy? Không phải việc của CSDL thì để cho CSDL làm chẳng phải sẽ nhanh hơn rất nhiều sao?

- Việc đó thì em nghĩ là đúng. Em cũng chưa từng tự hỏi vì sao họ lại khuyến cáo như vậy. Về phần em, cũng không thấy phiền hà lắm với việc xử lý tất cả trên PHP. Đôi khi còn rất hữu dụng nữa...

...

Về nhà em cũng suy nghĩ lại đoạn đó, vả cũng cố nghĩ ra một cách giải thích, các bác xem có hợp lý không nhé:

- Tất nhiên, khai thác triệt để các tính năng do CSDL mang lại là tốt nhất.

- Tuy nhiên khi phát triển các ứng dụng trên PHP và MySQL, các bác nhà ta thường chuẩn bị tư thế sẵn sàng cho việc ... vì lý do nào đó, thay đổi cơ sở dữ liệu sử dụng (từ MySQL sang Oracle chẳng hạn). Code tất cả các tính năng trong PHP giảm được sự phức tạp cho việc chuyển đổi này. Vì thế, MySQL chỉ được coi là thùng chứa dữ liệu, chứ các tính năng xử lý dựng sẵn không được coi trọng.

- Xử lý bằng PHP, về sau hệ thống cần phải chịu tải lớn, cần phải tối ưu hóa một số đoạn, việc refactor lại code sẽ dễ sàng hơn.

Có ai có thích giải thích khác không ạ? Các dự án mà các bác làm thì thế nào, có hay dùng TRIGGER & PROCEDURE của MySQL không? Trường hợp nào thì nên sử dụng TRIGGER & PROC?

Thứ Tư, 13 tháng 4, 2011

Submit file sử dụng iframe

Chắc các bạn cũng đã quen với việc dùng ajax để submit form mà không phải load lại toàn bộ trang.Với bài viết này mình sẽ hướng dẫn các bạn

Thứ Sáu, 1 tháng 4, 2011

Hướng dẫn cài đặt và sử dụng sock5

I.Cài đặt nylon sock server.
- Download nylon sock servar tại http://monkey.org/~marius/nylon/nylon-1.21.tar.gz (wget http://monkey.org/~marius/nylon/nylon-1.21.tar.gz)
- tar xvfz nylon-1.21.tar.gz
- cd nylon-1.21
- ./configure
- make
- make install

->Đến đây quá trình cài đặt nylon sock server đã hoàn tất.

+ Để tạo một socks ta sử dụng lệnh
nylon -p 12347 -i 75.126.162.150 -a 118.70.169.148 -I174.37.84.24
Trong đó:
- 12347 : cổng để truy xuất vào socks
- 75.126.162.150 : ip của server
- 118.70.169.148 :cho phép ip 118.70.169.148 truy suất được vào socks.
- 174.37.84.24 : ip hiển thị.
+ Số lượng socks sẽ tương ứng với lượng ip có trên server.

II.Sử dụng socks để kết nối vào các server whois lấy thông tin.
1.Download class socks5 tại : http://www.phpkode.com/source/s/socks5/socks5/class.socks5.php

Ví dụ về sử dụng class socks5
<?php
function whois($server,$domain)
{
error_reporting(E_ALL);
ini_set("display_errors", true);

include "class.socks5.php";

// ip server 75.126.162.150
// cong connect vao socks 12347
$socks5 = new socks5("75.126.162.150", 12347);

$socks5->set_timeout(10);
$socks5->set_dnstunnel(false);
$buffer = '';
if($socks5->connect($server, 43) === true)
{
$buffer = $socks5->request("$domain\r\n\r\n");
}
unset($socks5);
return $buffer;
}
echo "<pre>";
echo whois("whois.godaddy.com","eroticaofsapphic.com");
echo "</pre>";
?>

Để giả lập 1 sock dùng thử bạn connect vào server sử dụng lệnh : ssh -D 9999 root@domain  (Để connect vào sock bạn dung ip 127.0.0.1 cổng 9999)

Thứ Năm, 31 tháng 3, 2011

SWFmill - FlashLite for Mobile solution

Các dòng mobile hỗ trợ truyền tham số (params) qua URL hay qua thẻ nhúng Object rất hạn chế. SOFTBANK, DOCOMO, AU có cách truyền tham số khác nhau, việc tùy biến hiện thị FlashLite với các tham số hoặc load động bằng loadMovie gặp nhiều khó khăn (VD: Hiện thị tốt được trên DOCOMO thì AU và SOFTBANK ko hiện thị đc và ngược lại).

[caption id="attachment_67" align="aligncenter" width="530" caption="SWFmill chuyển đổi XML - SWF"]SWFmill chuyển đổi XML - SWF[/caption]

SWFmill là công cụ cho phép dịch 2 chiều XML và SWF. Các tham số của FlashLite có thể đưa vào từ XML và thông qua SWFmill, trả về kết quả duy nhất là 1 file swf với nội dung mong muôn đã được tùy biến. Việc này vừa giải quyết được vấn đề tham số và tùy biến FlashLite trên các JP-phone vừa tối ưu được dung lượng hiện thị vốn đã phải giói hạn nhiều trên mobile (<100KB)

Cài đặt và sử dụng SWFmill:
Chú ý: Hiện nay bản mới nhất của SWFmill là 0.3.1 tuy nhiên việc compile từ source của version này đang gặp lỗi (tác giả cũng chưa biết nguyên nhân). Nên dùng phiên bản 0.3.0.

Tải source code về:

$ wget http://www.swfmill.org/releases/swfmill-0.3.0.tar.gz
$ tar zxvf swfmill-0.3.0.tar.gz
$ cd ./swfmill-0.3.0/


Cài đặt các thư việc để compile:

~/swfmill-0.3.0$ yum install libxml2-dev
~/swfmill-0.3.0$ yum install libxslt-dev
~/swfmill-0.3.0$ yum install libfreetype6-dev
~/swfmill-0.3.0$ yum install libpng12-dev


Build và cài đặt:

~/swfmill-0.3.0$ ./configure
~/swfmill-0.3.0$ make
~/swfmill-0.3.0$ make install


Sau khi cài đặt, chạy sẽ gặp lỗi:

$ swfmill -h
swfmill: error while loading shared libraries: libswft.so.0: cannot open shared object file: No such file or directory


Cần chạy lệnh sau để set lại cấu hình:

$ /sbin/ldconfig


Hoàn tất cài đặt. Bây giờ có thể chạy swfmill để xem các lệnh có thể thực thi:

$ swfmill -h

Thứ Tư, 30 tháng 3, 2011

Solrphpclient,khởi tạo và lấy dữ liệu từ solr

Ở bài trước mình đã hướng dẫn cách cài đặt apache-tomcat và apache-solr,các bạn có thể xem tại đây : http://i-php.net/2011/03/h%c6%b0%e1%bb%9bng-d%e1%ba%abn-cai-d%e1%ba%b7t-va-c%e1%ba%a5u-hinh-apache-solr/.

Thứ Tư, 23 tháng 3, 2011

Translate với bing

Hiện nay việc dùng đa ngôn ngữ trong các website là một điều tất yếu,với các phần ngôn ngữ tĩnh thì bạn bỏ thời gian ra dịch là một điều hợp lý,nhưng với các nội dung động thì không hẳn lúc nào bạn cũng có một đội ngũ ngồi dịch những nội dung này.Vì vậy việc áp dụng các công cụ tự động dịch các nội dung này sẽ giúp bạn tiết kiệm nhiều thời gian và tiền bạc :D.Nhưng nó cũng có mặt hạn chế là câu cú và nội dung dịch còn sai nhiều,nhưng nhìn chung người đọc vẫn hiểu được nội dung bài viết của bạn nói vè cái gì :D.

Trước hết để sử dụng được bing translate bạn cần vào link sau  để dăng ký một appID. http://www.bing.com/developers/createapp.aspx

$appId = "*********1F2C7EE5EE7D5A85F59D43C"; //thay thế bằng appId của bạn vừa đăng ký
$from = "en"; //ngôn ngữ gốc
$to = "fr"; //ngôn ngữ cần dịch

$text = "chuỗi cần dịch";

$detectUri = "http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=".$appId."&text=".$text."&from=".$from."&to=".$to; //link trả về kết quả translate.

Giờ nhiệm vụ của bạn hết sức đơn giản dùng file_get_contents hoặc curl,.. để get nội dung translate về

vd :file_get_contents($detectUri);

Lưu ý: vì việc translate truyền dưới dạng url lên bạn cần phải sử lý dữ liệu truyền lên url một chút để link không bị lỗi do một số ký tự đặc biệt.

mình tạm thời dung cái này:

$text = preg_replace("/[^a-zA-Z 0-9.,;\=\-\_\'\"\<\>:\\ \/]+/"," ",$text);
$text = preg_replace("/[ ]+/","+",$text);

các thẻ trả về sẽ bị chuyển thành &lt; ,...

bạn cần replace chúng

$content = str_replace(array("&lt;","&gt;"), array("<",">"), file_get_contents($detectUri));

Dữ liệu trả về sẽ bị bao bọc bởi thẻ
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"></string>
bạn chỉ cần remove nó đi là xài được :D
$content = strip_tags($content,"<br><p><b><i><a><img>"); dung tạm cái này vì lười viết
regexp :D bạn liệt kê những thẻ muốn giũ lại là được :D
ok vậy là nội dung translate đã khá sạch sẽ,bạn chỉ cần insert và database là ok :D.

Thứ Ba, 22 tháng 3, 2011

OOP - một số lưu ý khi tạo class

Class bao gồm các đặc tả & hành vi nhằm mô tả thuộc tính của object. Dưới đây là một số lưu ý nhỏ nhưng hữu ích mà chúng ta có thể cân nhắc khi tạo mới một class nào đó.

1. dữ liệu nên là private.
2. dữ liệu nên được khởi tạo trong (các) hàm constructor.
3. tránh sử dụng quá nhiều kiểu dữ liệu cơ bản để mô tả, nên tách thành các class khác trong trường hợp này.
4. tên của class nên phản ánh chính xác nhất trách nhiệm & vai trò của nó.
5. một class không nên gánh vác quá nhiều việc.
6. nên sắp xếp việc khai báo các fields một cách có trật tự (theo tứ tự chữ cái, hoặc gom nhóm thành từng kiểu logic, kiểu dữ liệu ...).
7. có thể không phải tất cả các field đều có thể truy cấp (cần có hàm get/set)




    Phần thưởng:

    • ai trả lời được "tại sao?" cho các ý 1, 2, 5, 7 sẽ có quà :D

    • ai trả lời được câu trên và cho ví dụ được các ý 3, 4, 6 sẽ có quà to hơn :D--- mại dô!

    Thứ Ba, 15 tháng 3, 2011

    Thứ Hai, 14 tháng 3, 2011

    Hướng dẫn cài đặt và cấu hình apache solr

    Khi làm việc với dữ liệu lớn thì các câu lệnh search sử dụng like sẽ là một điều khung khiếp, để giảm tải được điều này và đảm bảo server của bạn giảm tải được khối lượng công việc thì solr là một giải pháp thay thế khá tốt.Với bài viết này mình không đi sâu quá về solr,mà chỉ giới thiệu một số cách cài đặt và cấu hình cơ bản để solr có thể chạy trên server của bạn.(chỉ áp dụng với server linux).

    Trước tiên bạn tải bản apache tomcat mới nhất  hiện tại :D:apache-tomcat-7.0.11

    wget http://mirror-fpt-telecom.fpt.net/apache/tomcat/tomcat-7/v7.0.11/bin/apache-tomcat-7.0.11.tar.gz.

    tar xvzf apache-tomcat-7.0.11.tar.gz //giải nén

    tải apache solr:

    wget http://mirror-fpt-telecom.fpt.net/apache//lucene/solr/1.4.1/apache-solr-1.4.1.tgz
    tar xvzf apache-solr-1.4.1.tgz //giải nén

    copy apache-solr-1.4.1.war trong apache-solr-1.4.1/dist vào apache-tomcat-7.0.11/webapps sau đó edit lại tên file thành solr.war

    cp /apache-solr-1.4.1/dist/apache-solr-1.4.1.war /apache-tomcat-7.0.11/webapps/solr.war

    vào thư mục bin của apache-tomcat-7.0.11 khởi động apache tomcat

    cd apache-tomcat-7.0.11/bin/

    ./startup.sh //khoi dong apache tomcat

    Tìm file web.xml trong apache-tomcat-7.0.11/webapps/solr

    cd ~

    cd apache-tomcat-7.0.11/webapps/solr

    nano web.xml

    sửa đoạn sau

    <env-entry>
    <env-entry-name>solr/home</env-entry-name>
    <env-entry-value>đường dẫn tuyệt đối tới thư mục /apache-solr-1.4.1/example/solr</env-entry-value>
    <env-entry-type>java.lang.String</env-entry-type>
    </env-entry>

    Việc tiếp theo chỉ cần khởi động lại apache tomcat la ok :).

    Để kiểm tra lại bạn vào linh http://localhost:8080/solr nếu xuất hiện dòng chữ

    Welcome to Solr!


    nghĩa là quá trình cài đặt của bạn đã thành công :D

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

    Create table using ul - li

    Ví dụ về cách dùng ul li để tạo bảng.

    HTML



    <ul>
    <li class="heading"><span>Table header</span></li>
    <li class="odd"><span>Row header 1</span></li>
    <li><span>Row header 2</span></li>
    <li class="odd"><span>Row header 3</span></li>
    <li><span>Row header 4</span></li>
    <li class="last"><span>Footer</span></li>
    </ul>
    <ul>
    <li class="heading"><span>Column header 1</span></li>
    <li class="odd"><span>Lorem ipsum</span></li>
    <li><span>Lorem ipsum</span></li>
    <li class="odd"><span>Lorem ipsum</span></li>
    <li><span>Lorem ipsum</span></li>
    <li class="last"><span>&nbsp;</span></li>
    </ul>
    <ul>
    <li class="heading"><span>Column header 2</span></li>
    <li class="odd"><span>Dolor sit amet</span></li>
    <li><span>Dolor sit amet</span></li>
    <li class="odd"><span>Dolor sit amet</span></li>
    <li><span>Dolor sit amet</span></li>
    <li class="last"><span>&nbsp;</span></li>
    </ul>
    <ul>
    <li class="heading"><span>Column header 3</span></li>
    <li class="odd"><span>Lorem ipsum</span></li>
    <li><span>Lorem ipsum</span></li>
    <li class="odd"><span>Lorem ipsum</span></li>
    <li><span>Lorem ipsum</span></li>
    <li class="last"><span>Footer data</span></li>
    </ul>

    CSS



    ul, li {
    margin: 0;
    padding: 0;
    list-style: none;
    }
    ul {
    float: left;
    }
    ul li {
    border-right: 1px solid #fff;
    border-bottom: 1px solid #fff;
    color: #fff;
    background: #87C409;
    }
    ul li.odd {
    background: #76AB07;
    }
    ul.first-col li {
    font-weight: bold;
    }
    ul li.heading {
    font-weight: bold;
    background: #5A8406;
    margin-top: 5px;
    }
    ul li span {
    padding: 10px;
    display: block;
    }

    /* hightlight */
    ul.hightlight li {
    background: #699906;
    }
    ul.hightlight li.heading {
    background: #415F03;
    margin-top: 0;
    padding-top: 5px;
    }
    ul.hightlight li.odd {
    background: #557B04;
    }

    /* footer */
    ul li.last {
    background: #5A8406;
    border: none;
    }
    ul.last-col li.last {
    text-align: right;
    }
    ul li.last span {
    padding: 5px 10px;
    }

    Kết quả:


    Untitled Document





    • Table header

    • Row header 1

    • Row header 2

    • Row header 3

    • Row header 4

    • Footer



    • Column header 1

    • Lorem ipsum

    • Lorem ipsum

    • Lorem ipsum

    • Lorem ipsum

    •  



    • Column header 2

    • Dolor sit amet

    • Dolor sit amet

    • Dolor sit amet

    • Dolor sit amet

    •  



    • Column header 3

    • Lorem ipsum

    • Lorem ipsum

    • Lorem ipsum

    • Lorem ipsum

    • Footer data




    Thứ Bảy, 5 tháng 3, 2011

    Faux Colums & Column 2-1-3

    Faux Column : là một kỹ thuật dùng để làm cho các thẻ div có chiều cao bằng nhau. (giống như khi ta dùng thẻ 'td' trong table)
    Sau đây là ví dụ :
    Chúng ta sẽ tạo ra 3 cột bằng cách dùng 5 thẻ div lồng nhau (main-content, main-content_1, main-content_2, main-content_3, main-content_4) và 3 thẻ div (content-center, content-left, content-right), 3 thẻ div này là phần nội dung sẽ được hiển thị. Ta sẽ quy định phần bên trái và bên phải sẽ có chiều rộng là 25%, còn phần giữa sẽ là 50%.)

    HTML :
    <div id="main-content">
    <div id="main-content_1">
    <div id="main-content_2">
    <div id="main-content_3">
    <div id="main-content_4">
    <div id="content-center"></div>
    <div id="content-left"></div>
    <div id="content-right"></div>
    <div class="clear"></div>
    </div>
    </div>
    </div>
    </div>
    </div>

    CSS :
    .clear {
    clear: both;
    }
    div#main-content {
    background: #a8a8a8;
    width: 960px;
    margin: 0 auto;
    }
    div#main-content_1 {
    background: #4200ff;
    }
    div#main-content_3 {
    background: #ff0c00;
    }


    Đặt các thẻ div vào vị trí mình mong muốn bằng cách sử dụng thuộc tính position: relative
    div#main-content {
    background: #a8a8a8;
    width: 960px;
    margin: 0 auto;
    position: relative;
    }

    div#main-content_1,
    div#main-content_2,
    div#main-content_3,
    div#main-content_4 {
    position: relative;
    width: 100%;
    }


    Đầu tiên chúng ta sẽ cho thẻ div : main-content_1 dịch sang bên trái là 75%
    div#main-content_1 {
    background: #4200ff;
    right: 75%;
    }


    Tiếp đến là cho thẻ div : main-content_2 dịch sang bên phải là 75% để trở về vị trí ban đầu
    div#main-content_2 {
    left: 75%;
    }

    Làm tương tự như vậy với thẻ div : main-content_3 và main-content_4 nhưng với vị trí lần lượt là phải và trái
    div#main-content_3 {
    background: #ff0c00;
    left: 75%
    }
    div#main-content_4 {
    right: 75%
    }


    Dùng thuộc tính overflow: hidden để ẩn đi phần thừa
    div#main-content {
    background: #a8a8a8;
    width: 960px;
    margin: 0 auto;
    position: relative;
    overflow: hidden;
    }


    Vậy là xong được 1 phần. Bây giờ sẽ là phần nội dung hiển thị. Ở phần này, mình sẽ sử dụng column : 2-1-3. Việc này khá tốt để làm SEO. Chúng ta sẽ đặt phần nội dung chính lên đầu tiên rồi tiếp đến là phần nội dung phụ.
    div#content-center,
    div#content-left,
    div#content-right {
    position: relative;
    }
    div#content-center {
    float: left;
    left: 25%;
    width: 50%;
    }
    div#content-left {
    float: left;
    left: -50%;
    width: 25%;
    }
    div#content-right {
    float: right;
    width: 25%;
    }

    Thêm 1 chút nội dung vào. Đây là kết quả




    Thứ Sáu, 4 tháng 3, 2011

    Lập trình yahoo messenger bot với php

    Đây là cách viết sử dụng qua officer api của yahoo .

    1. Đăng ký yahoo developer :

    http://developer.yahoo.com/

    2. Create 1 project . (Nhớ là non web project nhé)

    https://developer.apps.yahoo.com/projects

    Grant quyền access vào YM cho project
    Trong phần Permissions , kéo xuống tìm Yahoo! Messenger -> Full Access


    3. Download lib , implement sẵn api

    https://github.com/yahoo/messenger-sdk-php

    4.Sửa code 1 chút :

    Sửa file client.php

    define('USERNAME', 'ha_bogay'); // your username
    define('PASSWORD', 'xxxxxx'); // your password
    define('CONSUMER_KEY', 'dj0yJmk9UkhiejdNNHN5VjVhJmQ9cccWVdrOVMyZERUSE5hTm04bWNHbzlOREF6TURJMU5UWXkmcz1jb25zdW1lcnNlY3JldCZ4PTk4');
    define('SECRET_KEY', '1a895fdbb3847axxx8dc02cd38bf2b23bb88f2c522d');

    Riêng CONSUMER_KEY và SECRET_KEY lấy sau khi tạo project ở bước 2 .

    Chạy : php client.php

    Tiếp theo là chat với bot .
    Có thể sửa chương trình 1 chút để làm bot xịn , có kịch bản , hay là chương trình spam YM ...

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

    PHP_OPENSSL - gửi mail với SMTP server của google.

    Khi website của bạn hosts trên hosting của Nhân Hòa chẳng hạn. Các bác bên ấy thường quên không hỗ trợ thư viện php_openssl cho PHP, nên khi bạn cần sử dụng một kết nối tới địa chỉ như ssl://smtp.gmail.com:465 để gửi mail (việc này sẽ tránh được việc các mail của bạn bị đưa vào danh sách spam khi sử dụng các smtp server khác).

    Đơn giản là nên gọi và yêu cầu hỗ trợ thư viện php_openssl. Em đã từng gọi bên Nhân Hòa nhưng các bác ấy bảo  ... vì lý do bảo mật... Uhm, em không hiểu php_openssl thì ảnh hưởng gì đến bảo mật của các bác ấy. Đơn giản là vì thư viện này không mặc định được mở khi cài đặt PHP đúng không các bác.

    Using Nusoap with PHP

    Lâu lắm rồi ko có j` nổi bật trong công việc để viết bài :D
    Hôm nay, bài toán tôi cần giải quyết là lấy dữ liệu từ các sàn giao dịch Chứng Khoán.
    Mọi vẫn đề đều được giải quyết, đến khi tôi gặp site này : http://www.hsx.vn/hsx/HOSE_Livesecurity.htm
    Ở đây, dữ liệu được load ra bằng ajax, như vậy nếu dùng file_get_contents() thì sẽ ko thể lấy được gì.
    Sau 1 hồi mò mẫm thì ra cái service này, http://www.hsx.vn/LS_VSE/HoSTC_Service.asmx
    Các function để site load dữ liệu ra đều ở đây cả.
    => vấn đề bây giờ là phải tạo 1 Soap Client để làm việc với service, và tôi chọn Nusoap.
    - Download lib tại đây : http://sourceforge.net/projects/nusoap/
    - Download file này : http://www.hsx.vn/LS_VSE/GetDataProxy.aspx?service=HoSTC_Service.asmx

    Ở trong file GetDataProxy.aspx có các function cần dùng, gồm các param, title ....
    Cái tôi quan tâm là function GetLiveSecurity() và param f_time.

    Trong code php, ta làm như sau:


    require_once('lib/nusoap.php');
    $client = new nusoap_client('http://www.hsx.vn/LS_VSE/HoSTC_Service.asmx?WSDL', true);
    $result = $client->call('GetLiveSecurity',array('f_time'=>'true'));
    var_dump($result);
    ?>


    vậy là tôi đã có đầy đủ dữ liệu được site load ra, bây giờ việc còn lại là chặt chém cái $result ra, muốn lấy j` thì lấy \:d/

    Bài toán của tôi chỉ cần có vậy, nếu của bạn phức tạp hơn, cần nhiều hơn thì tham khảo thêm nhé.
    Link tham khảo: http://www.slideshare.net/fulvio.corno/web-services-in-php-using-the-nusoap-library

    Thao tác với DLL bằng Java

    Môi trường triển khai



    • JDK 1.6_0.16

    • Eclipse

    • JUnit

    • VC++ Express 2010



    Mục đích

    File Calc.dll được tạo ra và bao gồm hai phương thức với đặc tả như sau



    • int add (int a, int b)

    • int substract (int a, int b)



    Viết đoạn mã Java sử dụng sẵn hai phương thức đã được viết bằng VC++ và được dịch ra file dll.

    Quy định chung

    Một số tên gọi được giữ nguyên tiếng Anh thay vì viết tiếng Việt.

    Thuật ngữ

    Java = nền tảng Java & ngôn ngữ lập trình Java

    C/C++ = ngôn ngữ lập trình C/C++

    service(s) (trong tài liệu này) = các hàm viết bằng ngôn ngữ lập trình khác java

    Intermediate platform = lớp trung gian giao tiếp giữa ứng dụng viết bằng Java & ứng dụng viết bằng các ngôn ngữ lập trình khác.

    JNI (Java Native Interface) = lớp giao tiếp giúp JVM gọi các services được viết bằng ngôn ngữ lập trình khác.

    JNA (Java Native Access) = truy cập vào các thư viện native mà không phải viết code JNI

    Tổng quát

    Bản thân ngôn ngữ Java không tự gọi được các hàm viết bằng các ngôn ngữ lập trình khác. Vì thế, trong Java Platform có cung cấp Java Native Interface (JNI) cho phép tích hợp chương trình viết bằng Java với những services được tạo ra trên nền tảng khác. JNI định nghĩa các chuẩn đặt tên và cách thức gọi hàm tích hợp trong JVM.

    Kiến trúc



    [caption id="" align="aligncenter" width="571" caption="JNI architecture"]JNI architecture[/caption]




    Các bước gọi hàm trong file dll dịch từ C++



    • viết code java, bao gồm tên hàm & các tham số.

    • biên dịch file java = javac

    • tạo file header (*.h) = javah -jni

    • viết code C++ để thực thi, include file header tạo ra từ code java trên.

    • build mã nguồn C++ ra file dll

    • load file dll vào mã nguồn java và chạy.




    [caption id="" align="aligncenter" width="556" caption="Calling JNI"]Calling JNI[/caption]

    Trên là trường hợp lý tưởng khi có đủ cả mã nguồn & công cụ thực thi của các file dll. Tuy nhiên, trường hợp không thể có mã nguồn của dll mà chỉ có đặc tả kỹ thuật của các phương thức cần dùng thì công việc lại vất vả hơn chút. Đó là phải tự viết code C++ để đọc các

    phương thức từ dll, tức là tự viết lớp intermediate platform ở trên để làm việc kết nối Java & dll (lập trình bằng C/C++)

    Giải pháp khác

    Có nhiều thư viện giải quyết việc giao tiếp giữa mã nguồn Java & dll (C/C++), JNA là một trong số đó với đặc điểm dễ dùng & miễn phí. Những thông tin cần thiết bao gồm



    • download jna.jar

    • import vào dự án (giả sử dùng eclipse)

    • load dll lên và sử dụng, cần có đặc tả kỹ thuật của các phương thức (tên, tham số, kiểu dữ liệu nên chính xác)



    Làm bằng JNI đơn thuần

    1. Viết file Calc.java


    public native int add(int a, int b);

    public static void main(String[] args) {

    Calculator cal = new Calculator();

    int sum = cal.add(1,2);

    }

    2. Biên dịch file Calc.java


    javac Calc.java

    3. Tạo ra file header (*.h) để sử dụng trong mã nguồn C++


    javah -jni Calc

    File Calc.h thu được có nội dung như dưới


    #include <jni.h>

    /* Header for class Calculator */

    #ifndef _Included_Calculator

    #define _Included_Calculator

    #ifdef __cplusplus

    extern "C" {

    #endif

    /*

    * Class: Calculator

    * Method: add

    * Signature: (II)I

    */

    JNIEXPORT jint JNICALL Java_Calculator_add

    (JNIEnv *, jobject, jint, jint);

    #ifdef __cplusplus

    } #

    endif

    #endif

    Trong đó



    • JNIEXPORT jint JNICALL là quy tắc viết giao tiếp của JNI

    • jint là kiểu native của int



    4. Viết mã nguồn C++



    • #include file Calc.h header như trên

    • viết mã nguồn chính




    #include <jni.h>

    #include "Calc.h"

    JNIEXPORT jint JNICALL

    Java_Calc_add(JNIEnv *env, jobject obj, jint a, jint b)

    {

    return a + b;

    }

    5. Dịch mã nguồn C++ thành file dll. Trường hợp đã có sẵn file *.dll, từ bước (1) - (4) thì viết các phương thức theo như đặc tả kỹ thuật của file *.dll nhận được. Tại bước (4), viết các hàm C++ để gọi đến hàm C++ trong file *.dll đó.

    6. Sử dụng file dll vừa dịch trong mã nguồn Java.

    Cách này đòi hỏi người làm vừa phải làm với Java, vừa phải làm với C/C++. Nếu các lập trình viên Java ngại làm việc với C/C++ thì thư viện Java Native Access (JNA) là một trong số những lựa chọn tốt để sử dụng. Lợi ích của nó là có thể tránh cho lập trình viên can thiệp hoặc viết mới mã nguồn C/C++, tức là bỏ qua bước (3), (4) ở trên.

    Sử dụng JNA

    1. Vào website https://jna.dev.java.net/ và download thư viện cần thiết



    • jna.jar

    • platform.jar (không bắt buộc)



    2. Import thư viện jna.jar và viết mã nguồn java


    ○ file Calc.java

    package Calculator;

    import com.sun.jna.*;

    public interface Calc extends Library {

    int add(int a, int b);

    }

    ○ file Cal.java

    package Calculator;

    import com.sun.jna.*;

    public class Cal {

    static Calc init() {

    Calc c = (Calc) Native.loadLibrary("Path/to/Calc",

    Calc.class);

    return c;

    } public static void main (

    String [] args) {

    System.out.println(add(1, 2));

    } public static int add(int a, int b) {

    return init().add(a, b);

    } public static int substract(int a, int b) {

    return init().substract(a, b);

    }

    }

    Có thể gộp 2 files trên thành 1, tuy nhiên, việc viết interface mô tả các phương thức gọi các hàm native làm cho code dễ quản lý hơn.

    Vậy là chạy roài.

    Hai lỗi thường gặp



    • java.lang.UnsatisfiedLinkError: Error looking up function '<function’s name>': The specified procedure could not be found. -> kiểm tra lại chính xác tên hàm, kiểu dữ liệu (native) & tham số.

    • java.lang.UnsatisfiedLinkError: Unable to load library 'C:\Users\nguyen.duc.hoang\Documents\Visual Studio 2010\Projects\Calc\Debug\<library’s name>': The specified module could not be found -> kiểm tra lại tên file dll, đường dẫn đến file, phiên bản build & nền tảng lập trình của file đó.



    Hạn chế của JNA

    Tốc độ chậm hơn JNI native khoảng 10 lần (nghe nói thế), tuy nhiên vẫn có những cách để tăng thêm hiệu suất làm việc (chưa thử). Việc mapping giữa library & functions giữa JNA và native code cũng gặp vấn đề về



    • tính chính xác

    • các kiểu dữ liệu.



    Những yêu cầu của file *.dll dùng được



    • có mô tả chính xác tên hàm, giá trị trả về & tham số truyền vào.

    • có mô tả chi tiết các kiểu dữ liệu, hằng số

    • ngoài ra, file *.dll nên được viết (nếu = C/C++) đúng chuẩn xuất ra dll chứ không phải dll gắn trực tiếp & cố định vào một ứng dụng cụ thể (vì lý do ràng buộc giữ các thư viện - nếu có).

    • có thể xem được tên hàm của file *.dll bằng các chương trình phân tích dll đơn giản.



    Tham khảo thêm



    • website chính của dự án JNA https://jna.dev.java.net/

    • Sheng Liang The Java™ Native Interface (Programmer’s Guide and Specification)


    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ế .