SELECT BINARY trong MySQL

Hôm nay được chị tester thông báo 1 bug: Khi user login thì hệ thống không phân biệt username & password dạng chữ hoa, chữ thường :|

Câu query chỉ đơn giản là:

1
2
3
4
SELECT user_login	
FROM sys_user 
WHERE user_login = '$user_login' 
          AND user_passwd = '$password'

Hóa ra thằng MySQL nó không phân biệt chữ hoa, chữ thường nếu field type là varchar :-s

Cách fix: Có nhiều cách nhưng đơn giản nhất là “ép” về dạng binary để so sánh theo byte

1
2
3
4
SELECT user_login	
FROM sys_user 
WHERE BINARY user_login = '$user_login' 
          AND BINARY user_passwd = '$password'

Nguồn: http://dev.mysql.com/doc/refman/5.0/en/cast-functions.html#operator_binary

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

Generate data

Trước đây từng hơi bí với việc test performance với lượng dữ liệu lớn vì phía khách hàng họ “gợi ý” là dữ liệu tuy là để test nhưng cũng phải “đẹp” nữa, và họ không thích kiểu tên nhân viên có dạng như: employee 1, employee 2…

Hôm qua chả hiểu lang thang thế nào lại lạc vào trang Generatedata.com :D Quả thật là chỉ riêng việc họ cho mình 5 tùy chọn result type (HTML , Excel, XML, CSV, SQL) mình đã hạnh phúc lắm rồi :X ấy thế mà họ còn cho mình free download, không kèm bất cứ quảng cáo gì hay trail gì cả /:D/

Quá tuyệt >:D<

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

Accept only positive number using Jquery

Có thể sử dụng Event Handling hoặc Event Helper. Tất nhiên là sử dụng Event Helper thì ngắn hơn rồi :)

[-]?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
//when key is pressed in the textbox
$("#quantity").keypress(function (e)
{
  //if the letter is not digit then display error and don't type anything
  if( e.which!=8 && e.which!=0 && (e.which<48 || e.which>57))
  {
    //display error message
    $("#errmsg").html("Digits Only").show().fadeOut("slow");
    return false;
  }
});

Mình quen viết thế này hơn:

[-]?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
//when key is pressed in the textbox
$("#quantity").keypress
(
    function (e) {
        //if the letter is not digit then display error and don't type anything
        if( e.which!=8 && e.which!=0 && (e.which<48 || e.which>57)) {
            //display error message
            $("#errmsg").html("Digits Only").show().fadeOut("slow");
            return false;
        }
    }
);

Nguồn: http://roshanbh.com.np/2008/04/textbox-accept-only-numbers-digits.html

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

General Style and Syntax in CodeIgniter

http://codeigniter.com/user_guide/general/styleguide.html

Tạm đặt cái title đã, còn nhiều vấn đề với thằng này :D

PHP Closing Tag
Trong PHP có thể bỏ qua thẻ đóng ?>, điều này tránh được những lỗi vớ vẩn do bị output thừa :D Cái này chuẩn, không có gì phải bàn cả. Tuy nhiên 1 số IDE hơi man mát, phải có thẻ đóng nó mới hightlight code đc :|

Class and Method Naming
Class names should always have their first letter uppercase, and the constructor method should match identically. Multiple words should be separated with an underscore, and not CamelCased. All other class methods should be entirely lowercased and named to clearly indicate their function, preferably including a verb. Try to avoid overly long and verbose names.
Tên các lớp phải viết hoa chữ cái đầu tiên và phải giống với phương thức khởi tạo. Nếu tên lớp chứa nhiều từ thì sẽ được phân cách bởi dấu gạch dưới (underscore: _) và không được viết theo kiểu camelCase (làKiểuNhưThếNày). Các phương thức trong lớp phải viết thường, đặt tên có tính gợi nhớ, rõ ràng, nên có động từ đi kèm. Tránh việc đặt tên quá dài.

Okie, dịch phiên phiến là thế. Đồng ý là viết class xu hướng bây giờ người ta thường viết tên class dạng:

1
2
3
abstract class Zend_Pdf_Element {
   //...
}

Nhưng đấy là viết cho PHP5, dùng __autoload(), khi đó sẽ include từ thằng thư mục Zend, rồi Pdf, xong đến Element. Trong CodeIgniter (CI), khi viết class cần gì phải loằng ngoằng như vậy nhỉ? Cái ví dụ của nó còn chuối nữa :down:

1
2
3
4
5
6
INCORRECT:
class superclass
class SuperClass
 
CORRECT:
class Super_class

Variable Names
Phần này khá hợp lý rồi, không có gì để nói. Nhưng tôi khoái dùng camelCase chỗ này hơn.

Commenting
Chuẩn này quá chuẩn rồi :)>-

Constants
Tương tự trên

TRUE, FALSE, and NULL
Sẽ nói tới ở phần bên dưới.

Logical Operators
Các bác này đề nghị dùng OR thay cho || vì dùng || dễ nhầm với số 11 :lol: Uh nhỉ, cũng giống thật, mấy cái này tôi cũng không để ý nữa, căn bản có thằng IDE lo cho rồi, số và toán tử nó…khác màu nhau :-p
Tôi vẫn quen viết:

1
2
3
if(!$abc) {
    //...
}

giờ bảo viết

1
if ( ! $abc)

chắc tôi không nghe đâu, tự nhiên mất mấy lần gõ phím Space, tốn bao nhiêu Kalo chứ ít à :D

Comparing Return Values and Typecasting
Có lẽ đây là phần hay nhất & thuyết phục nhất bởi cái này không làm nhiều, không va vấp chắc không biết được :)

1
2
3
4
5
INCORRECT:
if (strpos($str, 'foo') == FALSE)
 
CORRECT:
if (strpos($str, 'foo') === FALSE)

Thoáng nhìn hẳn sẽ bảo tự nhiên cho thêm dấu = làm gì? Mất công gõ thêm 1 ký tự nữa :confused: Okie, theo như PHP manual, hàm strpos trong PHP sẽ trả về vị trí của chuỗi cần tìm kiếm trong chuỗi cho trước. Ví dụ nếu chuỗi ban đầu là: Đỗ Nam Khánh, tôi cần tìm từ Đỗ thì sẽ như sau:

1
2
$str = 'Đỗ Nam Khánh';
$pos = strpos($str, 'Đỗ');

Từ Đỗ nằm ở vị trí đầu tiên trong chuỗi (vị trí thứ 0) nên hàm này trả về giá trị 0, $pos = 0;
Vấn đề ở chỗ này đây:

1
2
3
if (strpos($str, 'foo') == FALSE)
sẽ tương đương
if (0 == FALSE)

Và dĩ nhiên, trong lập trình thì 0 là FALSE, khác 0 là TRUE. Vậy là, bác nào xui xẻo thì dính ngay trường hợp chết người này :)

Code Indenting
Chỗ này CI lại bắt ta quay về với kiểu cổ điển (Pascal chẳng hạn), ngày trước tôi cũng viết như vậy nhưng giờ hầu như là viết giống C:

1
2
3
foreach ($arr as $key => $val) {
   // ...
}

Đơn giản là lại bớt được 1 cái enter :”>

Những cái còn lại thì okie, thuyết phục :D

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

Cài font Windows cho Ubuntu

Dùng 1 trong 2 cách sau:

  1. Chép các fonts windows vào thư mục /usr/share/fonts/truetype
  2. sudo apt-get install msttcorefonts

Khởi động lại hoặc dùng lệnh sudo fc-cache -fv

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

Lấy bảng dự báo thời tiết

Dễ lắm :D Ngày xửa ngày xưa thì dùng đoạn Javascript của bên Vnexpress.net. Nhưng giờ ít ai dùng cái đó nữa vì nó quá đơn giản. Thế nên sẽ lấy ở các nguồn khác thôi. Chung quy lại, là nên lấy của thằng Trung tâm khí tượng thủy văn Việt Nam (http://www.nchmf.gov.vn) là chuẩn nhất (chuyện, của Việt Nam mà :p)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Get weather table
* @author Do Nam Khanh 
* @return string
*/
function _weather() {
	$content = file_get_contents('http://www.nchmf.gov.vn/website/vi-VN/43/Default.aspx');
 
	$strBegin 	= '<!-- Begin Display content -->';
	$strEnd 	= '<TD class="thoitiet_rightbox_ver"></TD>';
 
	$pos1 = strpos($content, $strBegin);
 
	if(false === $pos1) {
		return '';
	}
	else {
		$pos2 = strpos($content, $strEnd);
		$content = substr($content, $pos1, ($pos2-$pos1));
		return strip_tags($content, '<table><tr><td><img>');
	}
}

Demo: http://halongtours.vn/demo

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

Tạo một Country list (Drop down menu) kèm ảnh quốc kỳ

Chỉ đơn giản dùng CSS dạng như sau:

1
option#AF { background:url(images/flags/vn.png) no-repeat; padding-left:20px; }

Cái “khó” là phải:
- Có đủ ảnh các quốc gia trên thế giới
- File css cũng phải có từng đó định nghĩa option tương ứng

Để download bộ icon ảnh cờ các nước bạn có thể vào http://www.famfamfam.com/lab/icons/flags để tải, icon khá đẹp :)
Continue reading ‘Tạo một Country list (Drop down menu) kèm ảnh quốc kỳ’

Một PHP class tạo file ZIP

Tôi đang phải làm  chức năng nén/giải nén trong dự án hiện tại. Giải nén thì đã làm xong rồi, còn nén nữa là xong. Zip library của PHP hỗ trợ chức năng zip hơi bị kém, cái cơ bản nhất là cũng ngại phải viết => search & thấy class này khá nhẹ để nén 1 folder.

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
<?php
	require ("zipfile.inc.php");
 
	$zipfile = new zipfile();
 
	rec_listFiles('myFolder');
 
	header("Content-type: application/octet-stream");
	header("Content-disposition: attachment; filename=zipfile.zip");
	echo $zipfile->file();
 
	function rec_listFiles( $from = '.')
	{
		global $zipfile, $filedata;
 
		if(! is_dir($from))
			return false;
 
		if( $dh = opendir($from))
		{
			while( false !== ($file = readdir($dh)))
			{
				// Skip '.' and '..'
				if( $file == '.' || $file == '..')
					continue;
				$path = $from . '/' . $file;
				if( is_dir($path) ) {
					$zipfile->add_dir($path);
					rec_listFiles($path);
				}
				else {
					$filedata = implode("", file($path));
					$zipfile->add_file($filedata, $path);
				}
			}
			closedir($dh);
		}
	}
?>

Tạm đáp ứng yêu cầu :)

Source: http://www.devco.net/archives/2005/05/24/creating_zip_files_with_php.php

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

PHP post_max_size issue

Hôm nay tôi gặp phải 1 “tình huống” khá là củ chuối. Phần upload file (thật ra là upload file để update lại các store - khá nhiều, hiện tại là 1500 store) có validate file size, file type. Tôi test “khá kỹ ” ở local & mọi thứ đều ổn. Thông số local của tôi như sau:

  • Windows XP/Vertrigo
  • post_max_size = 100M
  • upload_max_size = 20M

Khi up 1 file có dung lượng quá 20MB (<100MB) thì hệ thống hiện thông báo rất đẹp với nội dung là bạn đã upload quá dung lượng quy định bla bla…:-@

Thế nhưng sau khi request done trên PMS (project management system), bên test report lại là khi upload 1 file lớn hơn 16MB thì chẳng hiện gì cả, không lỗi & giống như tự F5 lại trang.

Xem phpinfo của môi trường trên testing thì như sau:

  • post_max_size = 8M
  • upload_max_size = 16M

Vậy là dung lượng vượt quá post_max_size rồi, và PHP đã làm thế này đối với đoạn code của tôi:

If the size of post data is greater than post_max_size, the $_POST and $_FILES superglobals are empty

Thế cho nên đoạn code:

1
2
3
4
$postMaxSize = int_get('post_max_size');
if($postMaxSize < $userFile['size']) {
//process error
}

chẳng hoạt động gì cả :((
Trên php.net có 1 trick để xử lý trường hợp này:

This can be tracked in various ways, e.g. by passing the $_GET variable to the script processing the data, i.e.

, and then checking if $_GET['processed'] is set.

Và đây là đoạn code của tôi:

1
2
3
if(isset($_GET['processed']) && !count($_POST)) {
  die('Error message here...');
}

Chạy ngon ;)

Rất cảm ơn anh NBThanh (Nguyễn Bá Thành) đã giúp đỡ em khắc phục vấn đề này :)

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

Optimize performance

Dự án e-store tôi đang thực hiện đã sang phase II. Do đã tạo một số lượng không nhỏ các shop demo (khoảng 1500 - mặc dù yêu cầu là 5000 cái :() nên chức năng update toàn bộ các shop là chức năng bắt buộc phải có trong phase II này.

Ban đầu cứ nghĩ việc này khó, nhưng đến khi bắt tay vào làm mới thấy chẳng khó tý nào nếu không muốn nói là dễ :p

  1. 1 form để upload file (có validate, cấm các file execute như .sh, .exe…)
  2. File upload lên sẽ được copy vào toàn bộ các shop hiện có.
  3. Nếu file upload lên là dạng zip thì phải cho phép unzip & check như trường hợp 1

Với 3 yêu cầu này, không khó để thực hiện. Tuy vậy tôi vẫn bị vướng 1 chỗ & vẫn chưa nghĩ ra cách giải quyết nào triệt để, đó là vấn đề khi lấy toàn bộ các tên shop (shop code = thư mục) để copy file vào. Nếu trên môi trường Windows, chưa có cách nào khả thi hơn ngoài việc đọc dữ liệu trong DB. Cách này đơn giản nhưng khoảng thời gian để đọc từ DB ra cũng chẳng phải ít :( Còn trên Linux thì có vẻ dễ chịu hơn nếu như safe_mode = off :-” Tôi dùng command để đọc các thư mục shop hiện có, loại trừ đi mấy thư mục hệ thống. Hàm cụ thể 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
39
40
41
/**
* get all shop
* @author khanhdn
* @return array
*/
function getAllShop() {
	$shops = array('shop_temp');
 
	if(!isLinuxOS()) {
		$query = db_query("SELECT shop_code FROM {shop_setting} ORDER BY shop_code");
 
		while($rs = db_fetch_array($query)) {
			if(is_dir('../'.$rs['shop_code'])) {
				$shops[] = $rs['shop_code'];
			}
		}
	}
	else {
		$systemFolder = array(
							'system'
							,'sites'
							,'scripts'
							,'profiles'
							,'googlecheckout'
							,'themes'
							,'tmp'
							,'googleerror.log'
							,'googlemessage.log'
							,'index.php'
							,'mysqldumper'
							,'phpinfo.php'
						);
 
		$shopFolder = array();
		exec('cd ../; ls;', $shopFolder);
 
		$shops = array_diff($shopFolder, $systemFolder);
	}
 
	return $shops;
}

Thật ra thì đây chỉ là cách làm đối phó. Nếu hệ thống lớn chắc chắn vẫn không ổn. Chắc là phải làm việc ở mức thấp hơn nữa :-s

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