Monthly Archive for August, 2008

Upgrade whois domain to v3.1

Lý do phải nâng cấp:
- Matbao.net đã thay đổi lại cấu trúc site của họ (thay đổi giao diện) nên phần parse data của mình sẽ không chính xác nữa.
- Dùng nsloop-up chỉ có thể check domain đó có hoạt động hay không, chứ không check được đã được mua hay chưa. có thể chủ sở hữu đã mua nhưng chưa active domain :)

Những thay đổi:
Không có nhiều thay đổi trong phiên bản nâng cấp này ngoài:
- Get xml content thay cho html content.
- Chuẩn hóa các function theo camelCase.
- Bỏ php short tag, chuyển về <?php echo …;?> nếu có.

Todo:
Mặc dù kết quả nhận được từ matbao.net là dạng XML nhưng vẫn gặp khó khăn trong khâu parse XML. Dùng các libs có sẵn trong PHP như simpleXML, XMLparse…đều bị lỗi do syntax của file XML này không chuẩn cho lắm. Tạm thời tôi dùng preg_match để parse XML. Khi nào có điều kiện sẽ nghiên cứu cách parse XML mà không biết trước cấu trúc :D Có bác nào tốt bụng thì phát triển thêm hộ tôi với :p

Hướng dẫn nâng cấp:
- Download bản upgrade tại http://donamkhanh.com/download/whoisv3.1.php.txt
- Sau khi download, rename file whoisv3.1.php.txt thành index.php, rồi ghi đè file index.php trong thư mục whoisv3 (nếu chưa có phiên bản 3.0 thì có thể download tại http://donamkhanh.com/download/whoisv3.tar.bz2)

Yêu cầu:
- Chmod quyền hợp lý (cho đọc ghi đối với file checked_domain.txt)
- Thông số allow_url_fopen trên host phải thiết lập bằng On.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Discuss about Java

Chẳng mấy khi được nghe 2 cao thủ luận bàn, chẳng biết gì nên cứ copy về đây để bao giờ trình độ lên cao thì “nghiệm” vậy :”>

mega2look:
http://www.javavietnam.org/javavn/mvnforum/viewthread_thread,20372_offset,60#87886

Kính thưa các doanh nghiệp Việt Nam,

Hôm nay tôi xin thay mặt công ty SUN Microsystem gởi tới các đồng chí
lời chào thân ái và quyết thắng.

Chắc các đồng chí đều biết công ty chúng tôi là công ty hàng đầu về
bán server đã tối ưu để chạy công nghệ Java, dĩ nhiên công nghệ này
cũng của chúng tôi. Mặc dù tình hình kinh doanh của chúng tôi trong
những năm gần đây không được sáng sủa gì cho lắm, nhưng tôi đảm bảo
rằng chúng tôi vẫn là một trong những công ty hàng đầu trong vài năm
tới miễn là không thua lỗ nhiều quá, và đặc biệt là với sự ủng hộ vô
điều kiện của cộng đồng các nhà phát triển Java đầy tiềm năng tại Việt
Nam thì tương lai của SUN vô cùng sáng lạn.

Công ty chúng tôi chuyên cung cấp các giải pháp cỡ enterprise ở cả
phần mềm lẫn phần cứng. Trước hết tôi xin nói qua về giải pháp phần
mềm. Đây toàn là những phần mềm to vật vã, chức năng vô cùng khủng bố
hoàn toàn hợp với mác Enterprise mà các quí vị đang quan tâm. Để tạo
ra được phần mềm này các quí vị nên xem qua cái chuẩn J2EE (cũng do
chúng tôi định nghĩa ra nốt), nếu các vị chưa chóng mặt vì tầm mức vĩ
đại, kỳ vĩ của nó thì cũng sẽ phải thán phục trước độ phức tạp mà loài
người chưa từng hình dung ra từ trước tới nay.
Continue reading ‘Discuss about Java’

OpenSolaris 2008.05

Hồi trước vào blog của cậu Nguyên Vũ thấy cậu ấy “khoe” mới nhận được bản OpenSolaris từ Sun, cũng là 1 dạng request free CD giống Ubuntu nên quyết định đăng ký thử phát (mặc dù không có dùng Linux, nhưng mà đĩa xịn cơ mà, tội gì ).

Đăng ký xong và…quên béng mất thì tự nhiên hôm qua về nhà thấy lù lù 1 cái phong bì rất đẹp Thích thế

Cứ để dành đấy đã, bao giờ có laptop mình cài Linux vào dùng (hoặc hôm nào rảnh thì cài máy ở cty cũng được).

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Vì sao các PHP framework làm cho ứng dụng của bạn nặng nề hơn?

Lang thang được bài viết khá hay của bác Huy :)

Nếu bạn đã từng làm việc với các PHP framework như symfony, Cake, Zend … có thể bạn đã nhận ra những vấn đề này. Tôi xin nêu ra đây cả cách giải quyết của mình.

Việc sử dụng các pattern như Active Record, Data Mapping để làm Model trong các framework là một ác mộng.

Thật vậy, không những làm bạn khó khăn hơn trong việc xoay sở với SQL, nó còn khiến quá trình truy xuất dữ liệu trở nên nặng nề hơn. Các pattern này quy mỗi record trong database thành một object. Việc làm này là cực kỳ không cần thiết. Không phải lúc nào bạn cũng select chúng ra sau đó lại update trở lại database. Những logic nhằm bảo đảm mối quan hệ giữa các object cũng ngốn kha khá tài nguyên. Hơn nữa, các câu SQL được tự động sinh ra sẽ không đạt được mức độ tối ưu như mong muốn. Tối ưu SQL là một công việc quan trọng nhưng các ORM lại cố ngăn bạn khỏi công việc đó.

Giải pháp của tôi

Sử dụng DAO pattern để thay cho Active Record. Hoặc tốt hơn nữa là sử dụng các tính năng được hỗ trợ sẵn trong hệ quản trị cơ sở dữ liệu mà lâu nay lập trình viên PHP/(nhất là MySQL) thường quên đi mất như View, Trigger, Stored Procedured…  Bạn không nên lo ngại việc các lập trình viên của mình phải viết SQL. Suy cho cùng họ là lập trình viên, công việc của họ là viết code.

Lạm dụng sự tự động hoá.

Các framework thường tự động hoá một số giai đoạn trong workflow để trở nên thân thiện hơn đối với developer. Nếu bạn đã dùng qua CakePHP, bạn sẽ hiểu. Cake cho phép bạn khai báo các model và component bạn cần trong controller và tự động load toàn bộ chúng trong quá trình start-up. Điều này làm cho ứng dụng phải mất rất lâu để start-up. Hơn nữa, với cách phân chia ứng dung thành controller/action, bạn gặp phải một vấn đề là không phải lúc nào bạn cũng cần những model/component giống nhau ở tất cả các action trong cùng một controller. Với cách làm của CakePHP, bạn phải load những thứ mình không cần một cách bất đắc dĩ.

Giải pháp của tôi

Dẹp sự tự động hoá sang một bên đi! Hiện đại là hại điện. Tôi nhắc lại một lần nữa, bạn tuyển những lập trình viên và trả lương cho họ để họ viết code. Đừng ngại khi bắt họ làm chuyện đó.

Chính mô hình MVC làm tăng thêm các giai đoạn trong workflow của bạn

Ok, MVC là một mô hình tốt, chẳng ai phủ nhận cả. Nhưng việc phân chia rạch ròi giữa business logic (M) và presentation logic (V) cũng làm cho mọi thứ trở nên rắc rối hơn. Một ví dụ: trong mô hình MVC mà bạn gặp ở các framework mà tôi kể ở trên, Model thường xử lý dữ liệu xong rồi truyền cho View. Giả sử ở đây bạn có một list các bài hát cần in ra. Cách thông thường nhất và gần như duy nhất mà ta thường làm là Model nhận việc select từ database, duyệt qua tập kết quả lần để để tổng hợp nó thành một danh sách (ở PHP thì rất có thể là mảng) rồi sau đó mới truyền cho View. View lại phải duyệt qua mảng đó thêm một lần nữa để in ra.

Giải pháp của tôi

Tôi không có cách giải quyết nào và chấp nhận vấn đề này ở hiện tại. Thật ra nó cũng không ảnh hưởng quá nhiều đến performance, bù lại ta có được sự tách biệt rạch ròi về kiến trúc.

OOP

Lập trình OOP luôn luôn ngốn nhiều tài nguyên hơn so với function-based. Thêm vào đó, với đặc điểm của PHP, việc viết mỗi lớp thành một file riêng sẽ làm phân mảnh code và buộc PHP engine phải làm việc nặng nề hơn (nhất là đối với các framework như Zend).

Giải pháp của tôi

Sử dụng các opcode caching egine như APC, XCache.

Nguồn: byhuy.com

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Active Record Pattern

From Wikipedia, the free encyclopedia

In computer science, the active record pattern is a design pattern frequently found in software that stores its data in relational databases. It was named by Martin Fowler in his book Patterns of Enterprise Application Architecture.

Active record is an approach to accessing data in a database. A database table or view is wrapped into a class, thus an object instance is tied to a single row in the table. After creation of an object, a new row is added to the table upon save. Any object loaded gets its information from the database; when an object is updated, the corresponding row in the table is also updated. The wrapper class implements accessor methods or properties for each column in the table or view.

This pattern is commonly used by object persistence tools, and in object-relational mapping. Typically foreign key relationships will be exposed as an object instance of the appropriate type via a property.

Implementations of Active Record can be found in various frameworks for many programming environments. For example, if in a database there is a table parts with columns name (string type) and price (number type), and the Active Record pattern is implemented in the class Part, the following pseudo-code:

part = new Part()
part.name = "Sample part"
part.price = 123.45
part.save()

will create a new row in the parts table with the given values, and is roughly equivalent to the SQL command

1
INSERT INTO parts (name, price) VALUES('Sample part', 123.45);

Conversely, the class can be used to query the database:

b = Part.find_first_part("name", "gearbox")

This will create a new Part object based on the first matching row from the parts table whose name column has the value “gearbox”. The SQL command used would be

1
SELECT * FROM parts WHERE name = 'gearbox' LIMIT 1;

Để đó, chưa dịch :(

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Joomla 1.5.x remote admin password change

1 bug củ có thể nói là làm “bẽ mặt” Joomla team. Không thể ngờ Joomla lại có thể dính 1 lỗi chuối đến như vậy :-o

Thử với 1 site sử dụng Joomla version 1.5.2, mất 3 thao tác để vào được khu vực dành cho administrator :-T

Việc tiếp theo là thông báo bug cho ông anh admin với lời nhắn nhủ sau này em chụp ảnh cưới thì anh miễn phí cho em nhé - site kinh doanh áo cưới, ảnh cưới mà. Ông ấy đồng ý cái roẹt, sẽ free với điều kiện chú cưới lần 2 :)) Nham hiểm thế ko biết.

Kinh nghiệm rút ra:
- Khi setup 1 site, sử dụng os, phải bỏ hết các default setting đi.
- Với admin area, nên cho thêm 1 access layer nữa (.htpasswd chẳng hạn).

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Line endings

Thỉnh thoảng bị gặp lỗi rất củ chuối với các ký tự new line :( Do có sự khác biệt với mỗi hệ điều hành nên cần check cẩn thận:

  • Dos/Windows: \r\n
  • Unix: \n
  • Mac: \r

Tham khảo thêm tại: http://en.wikipedia.org/wiki/Line_endings

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Export to CSV file with Unicode

Ở bài trước tôi có đề cập đến việc export dữ liệu ra file CSV. Tuy nhiên, nếu export dữ liệu có chứa các ký tự Unicode thì sẽ không hiển thị được mặc dù khi mở bằng Notepad thì vẫn hiển thị đúng, tuy nhiên khi mở bằng Excel thì không hiển thị chính xác. Search trên mạng thấy giải pháp của anh Nguyễn Văn Hùng (Hưng?) đã giải quyết được (tôi mới test với German characters trong dự án Shop24 - rất okie).

Bài toán: export dữ liệu tiếng Việt UTF-8 thành file CSV có thể hiển thị đúng khi mở bằng Excel.
3 điểm dẫn đến thành công:
+ Dùng TAB (\t) thay cho COMMA (,) để phân tách các cột
+ Convert Encoding của dữ liệu cần output bằng UTF-16LE
+ Gắn chr(255)chr(254) vào đầu của kết quả cuối cùng trước khi output

PHP code đầy đủ (export order list):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
 * EXPORT ORDER LIST TO CSV FILE
 * @author khanhdn
 */
function exportCSV() {
	global $user;
	member_access();
 
	$memberInfo = member_info();
 
	$result = drupal_query("SELECT order_id
					,order_code
					,bill_firstname
					,bill_lastname
					,order_modify_date
					,gand_total
					,order_status
					 FROM {order}
					 WHERE shop_code = '".$memberInfo['shop_code']."'
					 ORDER BY order_creation_date DESC");
 
	$status_options = array(
                                '1'  => 'Neu'
				,'2' => 'In Bearbeitung'
				,'3' => 'Auf der Post'
				,'4' => 'Ausgeführt'
				,'5' => 'Zurück'
				);
 
	$csv = "Order code\tCustomer Name\tModify Date\tOrder Total\tOrder Status\r\n";
 
	if(count($result['data']))
	{
		foreach($result['data'] as $row)
		{
			$order_list = array(
							'order_code' 		=> "$row->order_code"
							,'customer_name' 	=> $row->bill_firstname. ' ' .$row->bill_lastname
							,'modify_date' 		=> mysqlTimestamp(strtotime($row->order_modify_date),'d.m.Y')
							,'order_total'		 => 'CHF '.$row->gand_total
							,'order_status'		=> $status_options[$row->order_status]
			);
 
			$csv .= join("\t", $order_list)."\r\n";
		}
 
	}
	$csv = chr(255).chr(254).mb_convert_encoding($csv, "UTF-16LE", "UTF-8");
 
	header("Content-type: application/x-msdownload");
	header("Content-disposition: csv; filename=" . date("Y-m-d") .
	"_order_list.csv; size=".strlen($csv));
	echo $csv;
	exit();
}

Source: Nguyễn Văn Hùng weblog

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Cài thêm 1 số plugin cho website

Hôm nay cài thêm mấy plugins sau cho website:D

  1. Subscribe to Comments
  2. Contact form
  3. PostRate
[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

PHP session in Drupal

Ít nhất 2 lần tôi đã từng sống dở chết dở với vấn đề chết session trong Drupal. Đang chạy ngon lại lăn đùng ra chết. Qua tìm hiểu mới biết, lý do như sau :(

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function sess_read($key) {
  global $user;
 
  // Write and Close handlers are called after destructing objects since PHP 5.0.5
  // Thus destructors can use sessions but session handler can't use objects.
  // So we are moving session closure before destructing objects.
  register_shutdown_function('session_write_close');
 
  // Handle the case of first time visitors and clients that don't store cookies (eg. web crawlers).
  if (!isset($_COOKIE[session_name()])) {
    $user = drupal_anonymous_user();
    return '';
  }
 
  // Otherwise, if the session is still active, we have a record of the client's session in the database.
  $user = db_fetch_object(db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = '%s'", $key));
 
  // We found the client's session record and they are an authenticated user
  if ($user &amp;&amp; $user-&gt;uid &gt; 0) {
    // This is done to unserialize the data member of $user
    $user = drupal_unpack($user);
 
    // Add roles element to $user
    $user-&gt;roles = array();
    $user-&gt;roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
    $result = db_query("SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d", $user-&gt;uid);
    while ($role = db_fetch_object($result)) {
      $user-&gt;roles[$role-&gt;rid] = $role-&gt;name;
    }
  }
  // We didn't find the client's record (session has expired), or they are an anonymous user.
  else {
    $session = isset($user-&gt;session) ? $user-&gt;session : '';
    $user = drupal_anonymous_user($session);
  }
 
  return $user-&gt;session;
}

Tức là Drupal lưu session trong Database, nếu là authenticated user thì sẽ lưu trong DB với uid tương ứng, còn không thì sẽ lưu với uid=0. Do vô tình (không cẩn thận), tôi đã xóa mất thằng uid=0 đó nên session die là đương nhiên :p

Từ giờ chắc sẽ không còn mắc cái lỗi đó nữa ^^

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]