10/10/2018, 11:18

Hướng đẫn kỹ thuật lập trình PHP & MySQL + Xtemplate

Mình rất ít khi viết bài trên các diễn đàn, tiện bữa nay đang chán nên muốn góp một chút ý kiến về PHP nói chung, nhưng bài này cũng có thể áp dụng với các ngôn ngữ khác, không biết những bạn đọc bài này có coi trọng về việc khả dụng của nó không, nhưng đối với mình, mình cảm thấy nó hợp lý nên chia sẻ. sau đây là bài hướng dẫn.

Những điều cần thiết sau đây.
1/ Có một IDE tốt, bạn có thể chọn một trong những IDE sau.
a> PHPED (đã có *****)
b> Zend studio (cũng ***** luôn)
c> Netbean (cái này free).
2/ Đã biết lập trình hướng đối tượng(nói chung) PHP(nói riêng), có một số kỹ thuật đơn giản nhưng có lẽ có bạn không để ý nên không biết.
3/ Kiên trì nhẫn nại

I/ Tạo Project
Điều này là rất quan trọng trong cách mà mình hướng dẫn sau đây, vì nó sẽ rất tiện lợi trong quá trình bạn làm việc sau này, vì khi đó tất cả các hàm, các lớp có trong project của bạn sẽ được hiển thị trên một menu tooltip
cách tạo project thì mỗi ide có một cách khác nhau, cái này bạn tự tìm hiểu nhé.

II/ Tạo thư viện.
Cái mình nói thư viện ở đây nó là một file để include vào mỗi trang, và chỉ cần 1 file duy nhất, vì cách mình làm đây phải tạo rất nhiều file thư viện tương đương với từng table của CSDL(Cơ sở dữ liệu) nên bạn có thể viết ra một file để include tất cả các file trong cùng thư mục vào, và sau này nếu cần dùng đến thư viện ta chỉ cần include file đó vào.
tạo một file Lib.php như sau trong folder /Lib:

PHP Code:
<?php
$path 
dirname(__FILE__);
function 
__IncludePath($p)
{
    
$handle opendir($p);
    if (
$handle) {
        while (
$file readdir($handle)) {
            if(
$file != "Lib.php" && $file != "." && $file != ".."){
                if(
is_file("$p\$file")) require_once($p.'.$file);
                else 
__IncludePath("$p\$file");
            }
        }
        
closedir($handle);
    }
}
__IncludePath($path);   
?>
File này có tác dụng include tất cả các file trong thư mục Lib và trong Folder con của nó.



III/ tạo một lớp kết nối MySQL

cái này cũng không cần thiết lắm, nhưng tốt nhất bạn cứ làm riêng ra cho dễ sử dụng và code một cách trong sáng hơn.


Bây giờ đã có file Lib.php, bạn có thể tạo các file với bất cứ tên gì và đặt trong Folder Lib.(cùng với file Lib.php)
đây là file của mình, bạn có thể tham khảo.

PHP Code:
<?php
    
class Config
    
{
        function 
Config(){
            
        }
        
        public static 
$host    "localhost";
        public static 
$user    "root";
        public static 
$pass    "admin";
        public static 
$data    "manager";

        public static 
$tbfix    "manager_";
        
        public static 
$count 0;
    }
       
class 
MySQL extends config
{   
  public static 
$conn NULL;   
  
  function 
MySQL()
  {
      
$this->connect();      
  }
  
  public static function 
connect() 
  {                               
      
self::$conn mysql_connect
      
self::$host,
      
self::$user,
      
self::$pass,      
      
TRUE  
    
)or die (mysql_error());
 
    
mysql_select_db(
        
self::$data
        
self::$conn
    
) or die (mysql_error());    
    
mysql_query("SET NAMES 'utf8'");
  }
 
  public static function 
disconnect() {
    if (
is_resource(self::$conn)){
      
mysql_close(self::$conn);
    }
  }
 
  public static function 
query($query){
      if (!
is_resource(self::$conn)) self::connect();
          
$result mysql_query(
            
$query,
            
self::$conn
          
) or die (Log::Write(array(
                
"Key1" => "ErroMySql",
                
"Key2" => "Query",
                
"Msg" =>  "<div> Câu lệnh thực hiện:<b>$query</b></div>Nội dung<div>".mysql_error()."</div>"
          
),null,true));
      if(
$result) return $result;
      return 
false;
  }          
  
  public static function 
select($table,$field=NULL,$where NULL,$orderBy NULL,$limit NULL){
      if(
strlen($table) != 0){
            if(
strlen($field) == 0$field '*';
          
$sql "select $field from ".self::$tbfix.$table;
        if(
$where != NULL$sql .= " where $where";
        if(
$orderBy != NULL$sql .= " order by ".$orderBy
        if(
$limit != NULL$sql .= " limit $limit";
        return 
self::query($sql);
    }
  }  

  public static function 
getCountRows($table,$where NULL)
  {   
      
$sql "select count(*) as rows from ".self::$tbfix.$table;
      if(
strlen($where)>0$sql .= " where $where";
      
$resultRows mysql_fetch_array(self::query($sql));
      return 
$resultRows***91;'rows'***93;;
  }
  
  public static function 
insert($table,$all){
      
$sql "insert into ".self::$tbfix.$table;
      
$i=0;
    foreach(
$all as $field => $value)
    {
      if(
$i>0)
      {
          
$fields .= ",";
        
$values .= ",";
      }
      
$value str_replace("'","'",$value);
      
$fields .= "$field";
      
$values .= "'$value'";
      
$i++;
    }
    
$sql "$sql ($fields) values ($values)";    
    if(
self::query($sql)) return self::LastID($table);
    return 
false;
  }
  
  public static function 
update($table NULL,$all NULL,$dk NULL){
      
//if($table)
      
if($dk != NULL){
        if(
self::getCountRows($table,$dk)==0)
        {
            
Log::Write(array(
                
"Key1" => "ErroMySql",
                
"Key2" => "NotFoundObjectUpdate",
                
"Msg" =>  "Bảng: $table<br> $dk<br>"
          
),$all,true);
            return;
        }
        
$sql "update ".self::$tbfix.$table." set";
        
$i=0;
        foreach(
$all as $field => $value)
        {
          if(
$i>0$up.=',';            
            
$value str_replace("'","'",$value);
          
$up .=$field = '$value'";
          
$i++;
        }
        
$sql "$sql $up where $dk";
        
        return 
self::query($sql);        
    }
  }
  
  public static function 
LastID($table)
  {
      
$result MySQL::query("SELECT LAST_INSERT_ID() AS lastInsertID FROM ".self::$tbfix.$table);
      
$row mysql_fetch_row($result); $rs $row***91;0***93;;
      return 
$rs;
  }
  
  public static function 
Del($table,$where){      
      
$sql "delete from ".self::$tbfix.$table." where $where";
    
self::query($sql);
  }
}                 
?>


tuy nó hơi loằng ngoằng mì tôm chút nhưng sau này công việc của bạn sẽ đỡ mệt hơn.



IV/ Tạo một lớp đại diện cho table trong CSDL
Điều này là rất quan trọng đối với hướng lập trình này,
Nó mang tất cả những điều cần có liên quan tới CSDL, ví dụ hàm insert, update, delete, select sẽ xuất hiện tất cả trong đối tượng này. tới bước này mình chưa thể giải thích tường tận, qua bước sau bạn sẽ hiểu nó quan trọng như thế nào, và bước này là bước phiền phức nhất, nhưng không sao, đối với lập trình hướng đối tượng bạn có thể cải thiện nó một cách dễ dàng mà không một một chút công sức nào. đây là file của mình, từ sau trở đi mình sẽ dựa vào nó để giải thích, bạn có thể làm theo một hướng tốt hơn đối với bạn.


PHP Code:
<?php 
class ObjectDB
{
    
/**
    * Các bạn nhớ kỹ, đối tượng ở lớp này mình nói ở đây là đại diện cho một dòng dữ liệu trong table.
    * Biến lưu trữ các cột trong đối tượng
    */
    
    
public $DB_Fields null//***91;0***93; Name, ***91;1***93; is auto, ***91;2***93; is PK(Lưu trữ các field trong CSDL sẽ khởi tạo sau)
    
public $DB_Table null// tên của Table cho đối tượng, sẽ khởi tạo sau
    
    
private $Limit null// khởi tạo sau khi gọi ham SetLimit(int $limit)
    
private $exist null// Xác định đối tượng có tồn tại hay không(biến lưu trữ, tránh trường hợp kiểm tra nhiều lần)
    
public $checkErrField// Biến Bol xác định có kiểm tra lỗi hay không(không quan trọng)
    
private $LastWhere// Lưu điều kiện cuối cùng khi sử dụng lệnh select, để đếm dòng thôi, không quan trọng
    
    /**
    * Phương thức khởi tạo
    * 
    * @access public
    * @param array()/Pk feild(int,string) $arr Khởi tạo các giá trị cho đối tượng(array()), lấy đối tượng nếu $arr = PK value
    * @param Bol $checkErr Thiết lập phương thức kiểm tra lỗi Feild, có hoặc không
    */
    
    
function ObjectDB($arr null,$checkErr true)
    {
        
$this->checkErrField $checkErr
        
$this->Install(); //sau khi khởi tạo, sẽ chạy hàm Install() để khởi tạo đối tượng, bạn sẽ hiểu sau.
        
$this->InstallField();// tạo field cho đối tượng sau khi nhận được field từ hàm Install()
        
if($arr)  //nếu truyền vào mảng sẽ gọi hàm SetValue để khởi tạo giá trị cho đối tượng
        
{
            
$this->SetValue($arr,$checkErr);
            if(!
is_array($arr)) $this->GetInfo();
        }
    }
       
    function 
Install(){} //Khai báo hàm phụ, không cần thiết, nhưng tránh cho khỏi lỗi nếu quên thôi
    
    
private function InstallField()
    {
//cái này đọc không hiểu thì mình cũng chịu, không biết giải thích thế nào
        
if(count($this->DB_Fields)==0$this->ShowErro("not set DB_Fields on Object <b>".get_class($this)."</b>"); // cái ShowErro này là chỉ là phụ thôi, báo lỗi ra cho đỡ phải tìm phiền phức
        
if(!$this->DB_Table$this->ShowErro("not set DB_Table on Object <b>".get_class($this)."</b>");
        foreach(
$this->DB_Fields as $field => $opt)
        {
            
$this->{$field} = null// gán field cho đối tượng. VD: khai báo Field ID thì khi đó sẽ có thêm Biến là $this->ID cách khai báo sẽ hướng đẫn ở dưới
        
}
    }
    
    
/**
    * lấy đối tượng từ database
    * 
    * @access public
    * @param string $where truyền vào điều kiện lấy dữ liệu, tự tạo bằng phương thức $this->SetFieldWhere();
    */
    
    
function GetInfo($where null// cái này chính là hàm select lấy một dựa vào điều kiện, nếu đã có PK(Primari key) thì không cần truyền $where
    
{
        if(!
$where$where $this->SetFieldWhere(); //lấy điều kiện với PK field, sẽ hiểu ở lớp dưới
        
if(!$where) return false;
        
$rs MySQL::select($this->DB_Table,"*",$where); // cái này phải cố hiểu thôi :(
        
$rs mysql_fetch_array($rs);
        if(!
$rs){
            
$this->exits false;
            return 
false;
        }
        
$this->SetValue($rs);// khi lấy được dữ liệu sẽ thiết đặt giá trị cho đối tượng
        
$this->exist true;
        return 
true;
    }
    
    
/**
    * Lấy danh sách đối tượng.
    * 
    * @access public
    * @param string $where truyền vào điều kiện lấy dữ liệu, lấy tất cả nếu null;
    * @param int $page Trang thứ $page trong lần lấy dữ liệu, bắt buộc thiết lập $limit qua $this->SetLimit($limit)
    * @param string/array() $order cách sắp xếp trong lần lấy dữ liệu, default theo Pk của đối tượng
    * @param ASC|DESC $by cach sap xep
    */
    
    
function Gets($where null,$page null,$order null,$by null//cái hàm này cũng tương tự như hàm trên, nhưng thay vào đó nó lấy ra một danh sách(array) đối tượng chứ không phải một đối tượng
    
{                                              
        
$bgRow $this->GetBgRow($page);//tính toán để lấy dòng bắt đầu select, nếu truyền vào $page, trước đó phải set $this->limit trước ($this->SetLimit(int $limit))
        
$limit null;
        if(
$page)
        {
            if(
$page<1$page 1;
            
$limit "$bgRow,".$this->Limit;
        }
        if(
$order)
        {
            
$field ';
            if(
is_string($order)) $field $this->CheckField($order); //kiểm tra xem truyền vào có đúng tên cột không, tránh trường hợp nó hack CSDL
            
elseif(is_array($order)) foreach($order as $f){ // có thể truyền vào một array
                
if($field$field .= ',';
                
$field .= $this->CheckField($f);
            }
            
            if(!
$field){//cái này là lớp riêng của mình để ghi lỗi, từ giờ bạn không cần quan tâm đến lớp này (Log)
                
Log::Write(array(
                    
'Key1' => 'ErroObject',
                    
'Key2' => 'NotFoundOrderField',
                ),
$order);
                return array(); 
// trả về array trống để tránh lỗi khi duyệt foreach()
            
}
        }
        if(
$by//kiểm tra xem truyền vào cách sắp xếp có đúng không
        
{
            
$by strtolower(str_replace(' ',',$by));
            if(
$by == 'asc' || $by == 'desc');
            else
            {
                
Log::Write(array(
              
longcuxit viết 13:32 ngày 10/10/2018
3/ Cập nhật dữ liệu
PHP Code:
<?php
include('Lib/Lib.php'); // include file thư viện

$cate = new CategoryObj(array(
    
"ID" => 1,
    
"Name" => "Thư viện",
    
"Comment" => "lời comment thứ nhất"
));

$cate->Update();

// quá trình cập nhật tương tự như quá tr ình insert, nhưng có một điều bạn phải chắc chắn là thiết đặt giá trị PK cho đối tượng hoặc truyền vào điều kiện cập nhật.

$cate = new CategoryObj(array(
    
"Name" => "Thư viện",
    
"Comment" => "lời comment thứ nhất"
));
$cate->Update('ID = 1');




$cate = new CategoryObj();
$cate->Update('ID = 1',array(
    
"Name" => "Thư viện",
    
"Comment" => "lời comment thứ nhất"
));




$cate = new CategoryObj();
$cate->Update('ID = 1',$_POST);

?>
Quá trình delete cũng tương tự
4/delete dữ liệu
PHP Code:
<?php
include('Lib/Lib.php'); // include file thư viện

$cate = new CategoryObj(array(
    
"ID" => 1
));
$cate->Delete();



$cate = new CategoryObj(1);
$cate->Delete();



$cate = new CategoryObj();
$cate->Delete('ID = 1');
?>
như vậy là tạm xong những quá trình thêm, xoá, sửa, ngoài ra bạn có thể thêm một số tùy biến cho đối tượng như lớp này của mình.
PHP Code:
<?php
class User extends ObjectDB
{   
      
    function 
Install()
    {
        
$this->DB_Fields = array(
            
"ID" => array(true,true),
            
"Acc"=> array(),
            
"Pass" => array(),
            
"Email"=> array(),
            
"Salt"=> array(),
            
"IsActive"=> array(),
            
"DateActive"=> array(),
            
"GroupID" => array(),
            
"Pass2" => array()
        );
    
        
$this->DB_Table "Users";
    }
    
    function 
Insert()
    {
        if(
$this->CheckEmail() && $this->CheckAcc())
        {   
            
$s = new Setting("UserGroupDefault");
            
$this->SetValue(array(
                
"Salt"=>$this->GenerateSalt(3),
                
"GroupID" => $s->Val
            
));            
            
$this->SetValue(array("Pass"=>$this->GenerateMd5Pass($this->Pass,$this->Salt)));
            
$this->SetValue(array("Pass2"=>$this->GenerateMd5Pass($this->Pass2,$this->Salt)));
            return 
parent::Insert();
        }
        return 
false;
    } 
    
    function 
Update()
    {
        
$this->SetValue(array("Salt"=>$this->GenerateSalt(3)));            
        
$this->SetValue(array("Pass"=>$this->GenerateMd5Pass($this->Pass,$this->Salt)));            
        
$this->SetValue(array("Pass2"=>$this->GenerateMd5Pass($this->Pass2,$this->Salt)));            
        return 
parent::Update();
    }
    
    private function 
CheckEmail()
    {
        
$u = new User();
        if(
$u->GetInfo("Acc = '".$this->Acc."'")) return false;
        return 
true;
    }
    
    private function 
CheckAcc()
    {
        
$u = new User();
        if(
$u->GetInfo("Email = '".$this->Email."'")) return false;
        return 
true;
    }
    
    function 
LogIn()
    {
        
$u = new User();
        if(
$u->GetInfo("Acc = '".$this->Acc."'")){
            if(
$this->GenerateMd5Pass($this->Pass,$u->Salt) == $u->Pass)
            {                        
                
//Dang nhap thanh cong
                
$_SESSION***91;"UserLogIn"***93; = $u->ToArray();
                
Log::Write(array("Key1" => "UserLogIn","Key2" => "Success","UserID"=>$this->Acc),$this->ToArray());
                return 
1;
            }
            else
            {
                
Log::Write(array("Key1" => "UserLogIn","Key2" => "WrongPass","UserID"=>$this->Acc),$this->ToArray());
                return 
2;
            }
        }else{
            
//Khong ton tai user
            
Log::Write(array("Key1" => "UserLogIn","Key2" => "NotExits"),$this->ToArray());
            return 
0;
        }
    }
    
    function 
LogOut()
    {
        unset(
$_SESSION***91;"UserLogIn"***93;);
    }
    
    private function 
GenerateSalt($max 32
    {
        
$baseStr time() . rand(01000000) . rand(01000000);
        
$md5Hash md5($baseStr);
        if(
$max 32){
            
$md5Hash substr($md5Hash0$max);
        }
        return 
$md5Hash;
    }
    
    private function 
GenerateMd5Pass($pass,$salt)
    {
        return 
md5(md5($pass).$salt);   
    }
}
?>
tới đây mình tạm nghỉ thôi, cũng hơi mệt rồi, về phần sau mình sẽ hướng dẫn cách bạn làm việc cùng với Xtemplate, viết theo kiểu này thật sự làm việc với xtemplate rất gọn và dễ dàng.

nếu có bạn nào quan tâm mình sẽ hướng dẫn tiếp vào lần sau, nếu như có người quan tâm mình sẽ hướng dẫn cho bạn viết theo cách quản lý module, control, tuy nhiều file một chút như nâng cấp, đính chính cập nhật rất dễ dàng.

vui lòng liên hệ yahoo nếu có thắc mắc, rất sẵn lòng, nếu ở TP HCM thì giới thiệu cho mình một cô bé dễ thương là được rồi đang chán như con gián đây


Chủ Quản: Phạm Hoàng long
Thân!

[=========> Bổ sung bài viết <=========]

Quên không cho cái yahoo: longcuxit


Chú ý: --------------------------------------------------------------
1/-- Về phần ObjectDB mình đã sửa lại một chút cho tiện dụng, tránh một số lỗi, tránh hack Database khi sử dụng dữ liệu từ client, bạn nào có hứng thú làm theo cách này thì liên hệ trực tiếp với mình.

2/-- Mình rất không chuyên về các mã nguồn mở, có vài người pm mình hỏi về các mã nguồn mở, để tránh mất thời gian cho mình cũng như các bạn, nên chú ý điều này. nhớ nhé, phải nói là đặc biệt không biết.

3/-- Ngoài ra mình cũng biết đôi chút về cách thiết kết html + css, đặc biệt, mình không nói là mình rồ nhưng mình làm rất nhiều với javascript, nếu bạn muốn hỏi về những vấn đề liên quan cũng có thể liên hệ mình.

4/-- Bài này mình đã nói rõ, nó rất thích hợp cho bạn khi làm việc cùng Xtemplate, chứ không phải mình quảng cáo cho bạn sử dụng Xtemplate, đã có rất nhiều bạn bàn luận về việc Xtemplate, nhưng nó đâu phải là vấn đề chính cho bài này, bạn có thể làm việc bằng cách khác, không ai bắt buộc bạn cả.

Cảm ơn các bạn đã theo dõi.
fotech_nd viết 13:19 ngày 10/10/2018
Pro ... vãi, bạn viết rất chi tiết - cố gắng lên nhé
longcuxit viết 13:22 ngày 10/10/2018
Mình sợ khi gõ code lên diễn đàn, bạn sẽ khó hiểu và copy bị lỗi nên mình làm ra một project sau, bạn tải về tham khảo.
không biết dễn đàn củ chuối hay do mình của chuối nữa, mình upfile không được, bạn vào link này nhé.

http://www.megaupload.com/?d=OK6AX6R7


nếu có bạn nào cần tiếp, mình sẽ hướng dẫn làm việc với xtemplate và làm việc theo mô hình quản trị USER Control, và module

Hoàng Long Thân!
vanlien129 viết 13:19 ngày 10/10/2018
Cám ơn anh,bài viết của anh rất hay và bổ ích, em cũng mới học PHP lên gà mờ nhiểu cái đọc vẫn không hiểu, xin được chỉ giáo thêm ạ.
longcuxit viết 13:20 ngày 10/10/2018
có gì thắc mắc bạn cứ pm trực tiếp với mình, mình không giúp ai bao giờ, nhưng đã giúp mình sẽ cố gắng hết mình. Y!m: longcuxit
rootkit viết 13:21 ngày 10/10/2018
tại sao phải sài template framework nhỉ, nó có lợi ích gì thê?
amida viết 13:24 ngày 10/10/2018
Được gửi bởi rootkit
tại sao phải sài template framework nhỉ, nó có lợi ích gì thê?
Template engine thì thích hợp hơn, nó ko đến nỗi là cái framework.

Còn tại sao dùng thì để tách markup/styling ra khỏi script
longcuxit viết 13:32 ngày 10/10/2018
Bạn hỏi như thế mình cũng không biết phải trả lời làm sao.
Mình cũng không hiểu tại sao mình phải dùng.
Ở đây không ai bắt buộc bạn phải dùng mà là nếu bạn thích thì dùng.

Mình không biết bạn hỏi chơi hay hỏi giỡn, nhưng tiện thì mình có ý kiến thế này.
Thứ nhất: mình cảm thấy khi làm một cái gì đó, nó rất dễ để chỉnh sửa giao diện.
Thứ hai: mình chỉ phải code một lần, thời gian còn lại mình chỉnh sửa giao diện chứ không cần vừa chỉnh giao diện vừa code.
Thứ Ba: mình làm rất nhiều javascript, nếu như nhìn một trang vừa lẫn lộn php + html + CSS + javascript thì quả thật rất khó là phân biệt.
Thứ tư: khó có một IDE hỗ trợ hoàn hảo những thứ đó, vì thế mình chọn nhiều IDE để làm việc khi làm 1 trang web. VD: mình chọn phped để gõ php, visual studio để gõ css, javascript, html.

Đó chỉ là ý kiến cá nhân của mình. mong đừng chém quá mà tội em:|
vanlien129 viết 13:27 ngày 10/10/2018
Em cũng đồng ý với ý kiến của anh Long, em cũng mới mò cái đó nhưng mà thấy nó dễ dùng và học cũng nhanh nữa. Tiện cho em hỏi nếu mình dùng Xtemplate liệu có bảo mật được như những Open Source hay Framework khác không nhỉ?
Em cám ơn!
Bài liên quan
0