Register Register Member Login Member Login Member Login Forgot Password ??
PHP , ASP , ASP.NET, VB.NET, C#, Java , jQuery , Android , iOS , Windows Phone
 

Registered : 109,036

HOME > บทความจากสมาชิก > ขอนำเสนอคลาส MySQL_Connection ตัวช่วยที่จะทำให้คุณเขียนโปรแกรมติดต่อฐานข้อมูล MySQL ได้ง่ายขึ้น (ใช้ MySQLi)



 
Clound SSD Virtual Server

ขอนำเสนอคลาส MySQL_Connection ตัวช่วยที่จะทำให้คุณเขียนโปรแกรมติดต่อฐานข้อมูล MySQL ได้ง่ายขึ้น (ใช้ MySQLi)



ติดตามบทความล่าสุดของผู้เขียนได้ที่ phpinfo() Facebook Page



ขอนำเสนอคลาส MySQL_Connection ตัวช่วยที่จะทำให้คุณเขียนโปรแกรมติดต่อฐานข้อมูล MySQL ได้ง่ายขึ้น (ใช้ MySQLi)

อย่างที่ทราบกันแล้วว่า ในขณะนี้ฟังก์ชั่น MySQL Functions ได้มีสถานะ deprecated ใน PHP5.5 แล้ว

จึงมึการแนะนำกันทั่วไปว่าให้เปลี่ยนมาใช้ MySQLi หรือ PDO
ซึ่งผมเองก็ได้เขียนบทความอธิบายการใช้ฟังก์ชั่น MySQLi เบื้องต้นไว้แล้วด้วย

แต่ปัญหาก็คือ ทั้งสองอย่างนั้นมีการใช้งานที่อาจจะดูยุ่งยากสำหรับมือใหม่ และไม่ได้ช่วยให้เขียน SQL ได้ปลอดภัยขึ้นหากไม่ใช้ feature ที่ค่อนข้างซับซ้อน เช่น prepared statement

การใช้ prepared statement เพื่อป้องกัน SQL Injection
$mysqli = mysqli_init(); $mysqli->real_connect('localhost', 'root', '', 'testdb'); // ให้ ? ใน query เป็นตัวแปรที่มาจากข้างนอก $stmt = $mysqli->prepare("SELECT * FROM `games` LIMIT ?"); // กำหนดให้ ? เป็นชนิด integer และ "เชื่อม" (bind) เข้ากับตัวแปร $limit $stmt->bind_param('i', $limit); // เมื่อกำหนดค่า ? ใน query ก็จะมีค่าเท่ากับ $limit $limit = $_POST['limit']; // ทำการรัน query $stmt->execute(); // อ่าน result ที่ได้จากการรัน $result = $stmt->get_result(); // ดึงข้อมูลแถวแรก $row = $result->fetch_assoc(); // แสดงผล print_r($row);


ซึ่งจะเห็นว่า มันค่อนข้างซับซ้อน โดยเฉพาะสำหรับมือใหม่

ผมจึงอยากขอนำเสนอตัวช่วย นั่นก็คือคลาส MySQL_Connection
เป็นคลาสที่ช่วยจัดการ query ที่ผมเขียนไว้ใช้เองเมื่อนานมาแล้ว โดยใช้ฟังก์ชั่น MySQLi เป็นฐาน

เป็นคลาสที่จำกัดความสามารถของ MySQLi ให้เหลือเพียงสิ่งที่ใช้เป็นประจำ
และช่วย escape ค่าที่มาจากผู้ใช้ หรือการ fetch ข้อมูลลง array ในการเรียกครั้งเดียว

การใช้ MySQL_Connection เพื่อป้องกัน SQL Injection เปรียบเทียบกับตัวอย่างก่อนหน้า
$mysql = new MySQL_Connection('localhost', 'root', '', 'testdb'); // ทำการแทนที่ %n ด้วยค่าของ $_POST['limit'] และดำเนินการรัน query พร้อมทั้งอ่านแถวที่ได้ลงตัวแปร $rows $rows = $mysql->queryAndFetchAll("SELECT * FROM `games` LIMIT %n", $_POST['limit']); // แสดงผลแถวแรก print_r($rows[0]);


และยังช่วย debug เพราะจะจบการทำงานทันทีหากไม่มีการดักจับ exception เมื่อเกิด error
พร้อมทั้งแสดง error message และ query ที่มีปัญหา

การนำไปใช้งานก็แค่ copy โค้ดข้างล่างนี้ไปบันทึกเป็นไฟล์ ตั้งชื่อตามใจชอบครับ (แต่ผมใช้ชื่อว่า mysql.php)
แล้วเรียกใช้งานด้วยการ require หรือ include ตามปกติครับ

แต่หากใครที่ต้องการศึกษาฟังก์ชั่น MySQLi ด้วยตัวเอง ไม่อยากใช้คลาสของผม
ลองดูบทความนี้ เลิกใช้ฟังก์ชั่น mysql_xxxxx() ที่ล้าสมัย (deprecated) และเปลี่ยนมาใช้ MySQLi กันดีกว่า ครับ (เขียนโดยผมเองเหมือนกัน)
ซึ่งก็อยากให้ลองอ่านดู เพราะถ้าต้องการเปลี่ยนจากฟังก์ชั่น MySQL แบบเก่า และหันมาใช้ MySQLi
บทความดังกล่าวจะตรงประเด็นมากกว่าครับ

MySQL_Connection
<?php
/**
 * MySQL_Connection
 * คลาสที่จะช่วยให้คุณเขียนโปรแกรมเชื่อมต่อกับฐาน MySQL ได้สะดวกและปลอดภัยขึ้น
 * ทั้งยังง่ายต่อการ debug เพราะจะจบการทำงานทันที หากมีข้อผิดพลาดเกิดขึ้นใน query
 * พร้อมทั้งแสดง error message และ query ที่มีปัญหาให้
 * Copyright (c) 2013, phpinfo.in.th (http://www.phpinfo.in.th)
 */
final class MySQL_Connection extends MySQL_Abstract
{

    protected $connection;

    public function __construct()
    {
        $this->connection = mysqli_init();

		if (func_num_args() > 2) {
			$args = func_get_args();

			if (isset($args[3])) {
				$this->connect($args[0], $args[1], $args[2], $args[3]);
			} else {
				$this->connect($args[0], $args[1], $args[2]);
			}
		}
    }

    protected function replaceStringCallback($matches, $newData = null)
    {
        static $data, $i;

        if (!isset($matches)) {
            $data = $newData;
            $i = 0;

            return;
        } elseif (isset($matches[1])) {
            $null = isset($matches[1][1]);

            if (isset($matches[2])) {
                $value = isset($data[$matches[2]]) ? $data[$matches[2]] : null;
            } else {
                $value = isset($data[$i]) ? $data[$i] : null;
                ++$i;
            }

            if (is_array($value)) {
                switch ($matches[1][0]) {
                case '%':
                    return implode(',', $value);
                case 'q':
                    foreach ($value as &$v) {
						$v = implode(
							'`.`',
							explode('.', preg_replace('/`/u', '``', $v))
						);
                    }

                    return '`' . implode('`,`', $value) . '`';
                case 'b':
                    foreach ($value as &$v) {
                        $v = $null && $v === null
                            ? 'NULL'
                            : ((bool) $v ? 'TRUE' : 'FALSE');
                    }

                    return implode(',', $value);
                case 'n':
                    foreach ($value as &$v) {
                        $v = $null && $v === null
                            ? 'NULL'
                            : (is_numeric($v) ? $v : 0);
                    }

                    return implode(', ', $value);
                case 's':
                    foreach ($value as &$v) {
                        $v = $null && $v === null
                            ? 'NULL'
                            : $this->escapeString($v);
                    }

                    return '\'' . implode('\',\'', $value) . '\'';
                }
            } else {
                switch ($matches[1][0]) {
                case '%':
                    return $value;
                case 'q':
					return '`'
						. implode(
							'`.`',
							explode('.', preg_replace('/`/u', '``', $value))
						)
						. '`';
                case 'b':
                    return $null && $value === null
                        ? 'NULL'
                        : ((bool) $value ? 'TRUE' : 'FALSE');
                case 'n':
                    return $null && $value === null
                        ? 'NULL'
                        : (is_numeric($value) ? $value : 0);
                case 's':
                    return $null && $value === null
                        ? 'NULL'
                        : '\'' . $this->escapeString($value) . '\'';
                }
            }
        }

        return $matches[0];
    }

	public function __get($name)
	{
		switch ($name) {
			case 'charset':
				$info = $this->connection->get_charset();

				return $info->charset;
			case 'errorCode':
				return $this->connection->errno;
			case 'errorMessage':
				return $this->connection->error;
			default:
				break;
		}

		return isset($this->$name) ? $this->$name : null;
	}

	public function __set($name, $value)
	{
		switch ($name) {
			case 'charset':
				$this->connection->set_charset($value);

				break;
			case 'errorCode':
			case 'errorMessage':
				break;
			default:
				$this->$name = $value;

				break;
		}
	}
	
	public function __isset($name)
	{
		static $names = array(
			'charset' => true,
			'errorCode' => true,
			'errorMessage' => true,
		);

		return isset($names[$name]);
	}

	public function connect($host, $username, $password, $dbname = null)
    {
        if (!@$this->connection->real_connect(
                $host, $username, $password, $dbname
            )
        ) {
            throw new MySQL_Exception($this->connection->connect_error);
        }
    }

    public function close()
    {
        $this->connection->close();
    }

    public function query($query, $params = null)
    {
        $result = $this->connection->query(
            isset($params)
                ? $query = $this->replaceString($query, $params)
                : $query
        );

        if ($result === false) {
			throw new MySQL_Exception($this->connection->error, $query);
        }

		return true;
    }

    public function queryAndFetch($query, $params = null, $columnKey = null)
    {
		if (($result = $this->queryResult($query, $params))) {
			$row = $result->fetch($columnKey);
			$result->free();

			return $row;
		}
    }

    public function queryAndFetchAll($query, $params = null, $columnKey = null,
		$indexKey = null
	) {
		if (($result = $this->queryResult($query, $params))) {
			return $result->fetchAll($columnKey, $indexKey);
		}
    }

    public function queryValue($query, $params = null)
    {
		if (($result = $this->queryResult($query, $params))) {
			$row = $result->fetch();
			$result->free();

			return $row[key($row)];
		}
    }

    public function queryResult($query, $params = null)
    {
        $result = $this->connection->query(
            isset($params)
                ? $query = $this->replaceString($query, $params)
                : $query
        );

        if ($result === false) {
			throw new MySQL_Exception($this->connection->error, $query);
        } elseif ($result === true) {
            return;
        }

		return $this->createResult($result);
    }

    public function escapeString($value)
    {
        return $this->connection->real_escape_string($value);
    }

    public function replaceString()
    {
        $args = func_get_args();
        $query = array_shift($args);

        if (count($args) === 1) {
            $args = is_array($args[0]) ? $args[0] : array($args[0]);
        }

        $this->replaceStringCallback(null, $args);

        return preg_replace_callback(
			'/
			\x27(?>\x5c\x5c\x27|\x27\x27|[^\x27])*\x27#\x63\x6f\x6f\x6b\x69\x70\x68\x70
			|\x22(?>\x5c\x5c\x22|\x22\x22|[^\x22])*\x22#\x63\x6f\x6f\x6b\x69\x70\x68\x70
			|\x60(?>\x60\x60|[^\x60])*\x60#\x63\x6f\x6f\x6b\x69\x70\x68\x70
			|\x25#\x63\x6f\x6f\x6b\x69\x70\x68\x70
			(\x25|\x71|(?>\x73|\x62|\x6e)\x6e?)?#\x63\x6f\x6f\x6b\x69\x70\x68\x70
			(?>\x5b([^\x5d]+)\x5d)?#\x63\x6f\x6f\x6b\x69\x70\x68\x70
			|\x25#\x63\x6f\x6f\x6b\x69\x70\x68\x70
			/ux',
            array($this, 'replaceStringCallback'),
            $query
        );
    }

    public function ping()
    {
        $this->connection->ping();
    }

}

final class MySQL_Result extends MySQL_Abstract
{

    protected $result;

    protected function __construct($result)
    {
        $this->result = $result;
    }

    public function __destruct()
    {
		$this->free();
    }

	public function __get($name)
	{
		switch ($name) {
			case 'numRows':
				return isset($this->result) ? $this->result->num_rows : 0;
			default:
				break;
		}

		return isset($this->$name) ? $this->$name : '';
	}

	public function __set($name, $value)
	{
		switch ($name) {
			case 'numRows':
				break;
			default:
				$this->$name = $value;

				break;
		}
	}

    public function fetch($columnKey = null)
    {
        if (!isset($this->result)) {
            return;
        }

        if (!($row = $this->result->fetch_assoc())) {
            $this->free();
        }

        if ($row) {
            return isset($columnKey) ? $row[$columnKey] : $row;
        }
    }

    public function fetchAll($columnKey = null, $indexKey = null)
    {
        if (!isset($this->result)) {
            return;
        }

        $rows = array();

        if (isset($columnKey)) {
            if (isset($indexKey)) {
                while (($row = $this->result->fetch_assoc())) {
                    $rows[$row[$indexKey]] = $row[$columnKey];
                }
            } else {
                while (($row = $this->result->fetch_assoc())) {
                    $rows[] = $row[$columnKey];
                }
            }
        } elseif (isset($indexKey)) {
            while (($row = $this->result->fetch_assoc())) {
                $rows[$row[$indexKey]] = $row;
            }
        } else {
            while (($row = $this->result->fetch_assoc())) {
                $rows[] = $row;
            }
        }

        $this->free();

        return $rows;
    }

	public function free()
	{
        if (isset($this->result)) {
            $this->result->free();
			unset($this->result);
        }
	}

}

final class MySQL_Exception extends Exception
{

	private $query;
	
	public function __construct($message = null, $query = null)
	{
		parent::__construct($message);
		$this->query = $query;
		set_exception_handler(array($this, 'displayError'));
	}
	
	public function displayError($exception = null)
	{
		if (!$exception) {
			return;
		}
		
		if ($exception !== $this) {
			throw $exception;
		}

		$t = $exception->getTrace();
		$traces = array();

		foreach ($t as $v) {
			$class = isset($v['class']) ? $v['class'] : '';
			
			if ($class === 'MySQL_Connection') {
				continue;
			}

			$traces[] = htmlspecialchars(
				"$v[file]($v[line]): "
				. $class
				. (isset($v['type']) ? $v['type'] : '')
				. "$v[function]()"
			);
		}
		
		$message = array('<h1>' . get_class($exception) . '</h1><hr />');
		
		if ($exception->getMessage()) {
			$message[] = '<p>' . htmlspecialchars($exception->getMessage()) . '</p><hr />';
		}
		
		if ($this->query) {
			$message[] = '<pre>' . htmlspecialchars($this->query) . '</pre><hr />';
		}
		
		if ($traces) {
			$message[] = '<ul><li>' . implode("</li><li>", $traces) . '</li></ul>';
		}
		
		$message = implode($message);

		if (headers_sent()) {
			echo $message;
			exit;
		}

		while (ob_get_level()) {
			ob_end_clean();
		}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?php echo get_class($exception); ?> Exception</title>
<style type="text/css">
/*<![CDATA[*/
body {
	background-color: #ffffff;
	font-family: Consolas;
	color: #000000;
}
pre, ul {
	border: #6e2142 solid 1px;
	border-radius: 6px;
	background-color: #f0d4db;
	font-family: Consolas;
	font-size: 14px;
	color: #6e2142;
	white-space: pre-wrap;
}
pre {
	padding: 8px;
}
ul {
	padding-top: 8px;
	padding-bottom: 8px;
}
/*]]>*/
</style>
</head>
<body>
<?php
echo $message;
?>
</body>
</html>
<?php
		exit;
	}
	
}

abstract class MySQL_Abstract
{

    final protected function createResult($result)
    {
        return new MySQL_Result($result);
    }

}


การเรียกใช้งาน
require 'mysql.php'; $mysql = new MySQL_Connection();


เชิญนำไปใช้งานและพัฒนาแก้ไขเพิ่มเติมได้เลยครับ
ขอเพียงให้เครดิตกันหน่อยนะครับ หากจะนำไปเผยแพร่ต่อ


Methods


connect()
ใช้เพื่อเชื่อมต่อกับ MySQL Server

connect($host, $username, $password [, $dbname]) $host ชื่อหรือ IP ของเซิร์ฟเวอร์ MySQL เช่น 'localhost', '127.0.0.1' $username ชื่อผู้ใช้ $password รหัสผ่าน $dbname (optional) ชื่อฐานข้อมูลที่จะใช้เป็นฐานข้อมูล default สำหรับทุกๆ query


require 'mysql.php'; $mysql = new MySQL_Connection(); $mysql->connect('localhost', 'root', 'password', 'default_db'); // บรรทัดข้างบนจะเทียบเท่ากับการเขียนแบบเก่า // mysql_connect('localhost', 'root', 'password'); // mysql_select_db('default_db');


หรือ เรียกใช้ตั้งแต่ตอน new เลย

require 'mysql.php'; $mysql = new MySQL_Connection('localhost', 'root', 'password', 'default_db');


หมายเหตุ ควรจะเลือกฐานข้อมูล default ไว้ตลอด เพราะ MySQLi ไม่มีฟังก์ชั่นอย่าง mysql_select_db()
หากต้องการเปลี่ยนฐานข้อมูล default ต้องใช้ SQL USE

$mysql->query("USE `dbname`");





close()

ตัดการเชื่อมต่อกับ MySQL Server

$mysql->close();





query()

ส่งคำสั่ง SQL ไปให้เซิร์ฟเวอร์ MySQL ประมวลผล

query($query [, $params]) $query ชุดคำสั่ง SQL $params (optional) ค่าของตัวแปรที่ใช้แทนที่ %xx ใน $query เป็น string หรือ array ก็ได้ (ดู replaceString() เพิ่มเติม)


method นี้คืนค่ากลับมาเป็น true เสมอ เหมาะสำหรับใช้กับพวกคำสั่ง INSERT, UPDATE, DELETE และคำสั่งอื่นๆ ที่ไม่มีข้อมูลคืนกลับมา

$mysql->query( "UPDATE `table` SET `column1` = `column1` + %n", 4 // แทนที่ %n โดยกำหนดให้เป็นชนิดตัวเลข ); // จะเท่ากับ UPDATE `table` SET `column1` = `column1` + 4 $mysql->query( "UPDATE `table` SET `column2` = %s", 'CookiePHP' // แทนที่ %s โดยกำหนดให้เป็นสตริง ); // จะเท่ากับ UPDATE `table` SET `column2` = 'CookiePHP' $mysql->query( "INSERT INTO `table` (`column1`, `column2`) VALUES (%n, %s)", array( 500, // แทนที่ %n "Cookie's cat" // แทนที่ %s ), ); // จะเท่ากับ INSERT INTO `table` (`column1`, `column2`) VALUES (500, 'Cookie\'s cat')





queryAndFetch()

ส่งคำสั่ง SQL ไปให้เซิร์ฟเวอร์ MySQL ประมวลผล พร้อมกับดึงข้อมูลกลับมา 1 แถว (ถ้ามี)
แต่จะคืนค่ากลับมาเฉพาะ query ที่เป็นคำสั่งดึงข้อมูล เช่น SELECT หรือ SHOW เท่านั้น
คำสั่งอื่นๆ ที่ไม่มีการดึงข้อมูล เช่น INSERT หรือ UPDATE จะคืนค่ากลับมาเป็น null เสมอ
และหากไม่มีข้อมูล ก็จะคืนค่ากลับมาเป็น null เช่นกัน

queryAndFetch($query [, $params [, $columnKey]]) $query ชุดคำสั่ง SQL $params (optional) ค่าของตัวแปรที่ใช้แทนที่ %xx ใน $query เป็น string หรือ array ก็ได้ $columnKey (optional) ชื่อคอลัมน์ในตารางที่ต้องการจะให้เป็นค่าที่คืนกลับไป


คืนค่ากลับมาเป็น array ของข้อมูลแถวในตาราง
แต่หากมีการกำหนด $columnKey จะคืนค่ากลับมาเป็น string
หรือ null ถ้าเป็นคำสั่งที่ไม่มีข้อมูลกลับมา หรือไม่มีข้อมูล

ตัวอย่าง
$first_game_found = $mysql->queryAndFetch("SELECT * FROM `games`"); // จะ SELECT เจอกี่แถวก็ตาม แต่จะดึงมาเฉพาะแถวแรกเท่านั้น print_r($first_game_found);

ผลลัพธ์
Array ( [id] => 1 [released] => 2012-09-20 [title] => Pro Evolution Soccer 2013 [price] => 1090 )


ตัวอย่างการใช้ $columnKey
$released = $mysql->queryAndFetch( "SELECT * FROM `games` WHERE `title` = %s", 'Pro Evolution Soccer 2013', // แทนที่ %s 'released' // ดึงเฉพาะคอลัมน์ `released` ออกมา ); // $released จะเป็น string ไม่ใช่ array สามารถใช้ได้ทันที echo "This game was released on $released.";

ผลลัพธ์
This game was released on 2012-09-20.





queryAndFetchAll()

ส่งคำสั่ง SQL ไปให้เซิร์ฟเวอร์ MySQL ประมวลผล พร้อมกับดึงข้อมูลกลับมาทั้งหมด
แต่จะคืนค่ากลับมาเฉพาะ query ที่เป็นคำสั่งดึงข้อมูล เช่น SELECT หรือ SHOW เท่านั้น
คำสั่งอื่นๆ ที่ไม่มีการดึงข้อมูล เช่น INSERT หรือ UPDATE จะคืนค่ากลับมาเป็น null เสมอ

queryAndFetchAll($query [, $params, [, $columnKey [, $indexKey]]]) $query ชุดคำสั่ง SQL $params (optional) ค่าของตัวแปรที่ใช้แทนที่ %xx ใน $query เป็น string หรือ array ก็ได้ $columnKey (optional) ชื่อคอลัมน์ในตารางที่ต้องการจะให้เป็นค่าที่อยู่ใน array แทนที่จะเป็น array ของแถว $indexKey (optional) ชื่อคอลัมน์ในตารางที่ต้องการจะใช้เป็น key ของแต่ละแถวใน array ที่คืนกลับไป


ตัวอย่าง
$games = $mysql->queryAndFetchAll("SELECT * FROM `games` ORDER BY `released` LIMIT 5"); print_r($games);

ผลลัพธ์
Array ( [0] => Array ( [id] => 2 [released] => 2009-10-13 [title] => Uncharted 2: Among Thieves [price] => 1790 ) [1] => Array ( [id] => 21 [released] => 2009-10-13 [title] => Way of the Samurai 3 [price] => 1690 ) [2] => Array ( [id] => 20 [released] => 2010-10-26 [title] => Grand Theft Auto 4: Complete Edition [price] => 1790 ) [3] => Array ( [id] => 19 [released] => 2011-02-22 [title] => Killzone 3 [price] => 1090 ) [4] => Array ( [id] => 8 [released] => 2011-10-11 [title] => Ace Combat: Assault Horizon [price] => 1090 ) )


ใช้ $columnKey เพื่อดึงเฉพาะข้อมูลคอลัมน์ที่ต้องการออกมา
$titles = $mysql->queryAndFetchAll( "SELECT * FROM `games` LIMIT 10", null, // ไม่ใช้ 'title' // ดึงเฉพาะ title ออกมา ให้เป็นข้อมูลของแต่ละแถว ); print_r($titles);

ผลลัพธ์
Array ( [0] => Pro Evolution Soccer 2013 [1] => Uncharted 2: Among Thieves [2] => UnCharted 3: Drake'S Deception [3] => Syndicate [4] => Dead Island: Riptide [5] => Max Payne 3 [6] => Ninja Gaiden 3: Razor's Edge [7] => Ace Combat: Assault Horizon [8] => Rayman Origins [9] => The Walking Dead: A TellTale Game Series )


ใช้ $indexKey เพื่อทำให้ค่าของคอลัมน์ที่กำหนด เป็น key ของแต่ละแถว
$titles = $mysql->queryAndFetchAll( "SELECT * FROM `games` LIMIT 3", null, // ไม่ใช้ null, // ไม่ใช้ 'title' // กำหนดให้ title เป็น key ); print_r($titles);

ผลลัพธ์
Array ( [Pro Evolution Soccer 2013] => Array ( [id] => 1 [released] => 2012-09-20 [title] => Pro Evolution Soccer 2013 [price] => 1090 ) [Uncharted 2: Among Thieves] => Array ( [id] => 2 [released] => 2009-10-13 [title] => Uncharted 2: Among Thieves [price] => 1790 ) [UnCharted 3: Drake'S Deception] => Array ( [id] => 3 [released] => 2011-11-01 [title] => UnCharted 3: Drake'S Deception [price] => 1790 ) )


ใช้ทั้ง $columnKey และ $indexKey ร่วมกัน
$prices = $mysql->queryAndFetchAll( "SELECT * FROM `games` LIMIT 10", null, // ไม่ใช้ 'price', // ให้ price เป็นข้อมูล 'title' // ให้ title เป็น key ); print_r($prices);

ผลลัพธ์
Array ( [Pro Evolution Soccer 2013] => 1090 [Uncharted 2: Among Thieves] => 1790 [UnCharted 3: Drake'S Deception] => 1790 [Syndicate] => 1090 [Dead Island: Riptide] => 1890 [Max Payne 3] => 1190 [Ninja Gaiden 3: Razor's Edge] => 1690 [Ace Combat: Assault Horizon] => 1090 [Rayman Origins] => 1390 [The Walking Dead: A TellTale Game Series] => 1390 )





queryResult()

เป็น method ที่จะคืนผลลัพธ์กลับมาเป็น instance ของคลาส MySQL_Result
ซึ่ง method นี้เพื่อให้สามารถเขียนโปรแกรมในลักษณะเดิมได้
และจะช่วยประหยัดหน่วยความจำในกรณีที่ต้องการอ่านข้อมูลจำนวนมาก ที่หากใช้ queryAndFetchAll() แล้วจะทำให้เปลืองหน่วยความจำ

queryResult($query [,$params]) $query ชุดคำสั่ง SQL $params ค่าของตัวแปรที่ใช้แทนที่ %xx ใน $query เป็น string หรือ array ก็ได้ (ดู replaceString() เพิ่มเติม)


การเขียนโปรแกรมด้วยฟังก์ชั่น mysql_xxxxx() แบบเดิม
$result = mysql_query("SELECT * FROM `table`"); while (($row = mysql_fetch_assoc($result))) { // do something } mysql_free_result($result);


การเขียนโปรแกรมด้วย queryResult()
$result = $mysql->queryResult("SELECT * FROM `table`"); while (($row = $result->fetch())) { // do something }


จะเห็นว่าความแตกต่างระหว่างแบบเก่ากับแบบใช้ queryResult() นั้นอยู่ที่ mysql_free_result($result);
ซึ่งจริงๆ แล้ว MySQL_Result ก็มี method free() ไว้เพื่อทำหน้าที่เดียวกันกับ mysql_free_result()
แต่ถ้าเขียนแบบนี้ก็ไม่จำเป็นต้องเรียก free() เพราะหากไม่มีข้อมูลให้อ่านแล้วการเรียกใช้ fetch() จะเรียก free() ให้เอง

คลาส MySQL_Result มี method แค่ 3 ตัวคือ fetch(), fetchAll() และ free()

fetch() จะคืนค่ากลับมาเป็นข้อมูลที่ยังเหลือทีละแถว หากไม่มีข้อมูลให้อ่านแล้ว จะเรียกใช้ free() และคืนค่ากลับมาเป็น null
fetchAll() จะคืนค่ากลับมาเป็นข้อมูลที่ยังเหลือทั้งหมด และเรียกใช้ free()
free() ทำลายข้อมูลที่ยังไม่ได้อ่านทิ้ง และคืนหน่วยความจำให้กับระบบ

และมี property เพียง 1 ตัวคือ $numRows

echo จำนวนแถวที่หาได้
$result = $mysql->queryResult("SELECT * `table`"); echo $result->numRows;





ping()

ส่งสัญญาณไปบอก MySQL Server ให้คงการเชื่อมต่อไว้ เพราะหากไม่ได้มีการส่ง query ไปในช่วงเวลาที่เซิร์ฟเวอร์กำหนด การเชื่อมต่อจะถูกตัดขาดลง

$mysql->ping();





escapeString()

escape ค่าที่ต้องการให้เป็นสตริงที่ปลอดภัยที่จะใช้ใน query

escapeString($value) $value ค่าที่ต้องการ escape


ตัวอย่าง
$safe_string = $mysql->escapeString($_POST['username']);





replaceString()

แทนที่ตัวแปรลงในรูปแบบที่กำหนด เพื่อสร้าง query ที่ปลอดภัย ไร้ SQL Injection
รูปแบบการใช้งานจะดูคล้ายฟังก์ชั่น sprintf() อยู่มาก แต่จริงๆ แล้วไม่เหมือนกัน
ทุก query method ที่มี $params เป็น argument ก็จะมีการเรียกใช้ method นี้

replaceString($format, $params [, $...]) $format คือสตริงที่เป็น template มีรูปแบบที่กำหนดไว้ให้แทนที่ $params คือค่าที่ต้องการจะนำไปแทนที่ หากมีหลายค่า สามารถใช้เป็น array ได้ $... คือค่าอื่นๆ ที่จะนำไปแทนที่หากไม่ต้องการส่งค่าหลายๆ ค่าด้วย $params ที่เป็น array


ตัวอย่าง
$query = $mysql->replaceString( "SELECT * FROM %q WHERE `released` > %s LIMIT %n", 'games', // แทนที่ %q '2013-01-01', // แืทนที่ %s 10 // แทนที่ %n ); echo $query;

ผลลัพธ์
SELECT * FROM `game` WHERE `released` > '2013-01-01' LIMIT 10


จากตัวอย่างข้างบน จะเห็นว่า ตัวแทนที่คือ %q, %s และ %n


ตัวแทนที่


method ที่เกี่ยวกับการ query ทั้งหมด
จะมี $params เป็น argument ซึ่งใช้เป็นตัวแปรที่จะแทนที่ตัวแทนที่ใน $query
ประโยชน์ของตัวแทนที่คือ สามารถสร้าง query ที่ปลอดภัยจาก SQL Injection ได้โดยสะดวก
และได้โค้ด SQL ที่อ่านง่าย สบายตา หาที่ผิดและแก้ไขได้ไม่ยาก

สร้าง INSERT query โดยใช้การแทนที่แบบเรียงลำดับ
$mysql->query( " INSERT INTO `games` (`released`, `title`, `price`) VALUES (%s, %s, %s) ", array( $_POST['released'], // แทนที่ %s ตัวที่ 1 $_POST['title'], // แทนที่ %s ตัวที่ 2 $_POST['price'], // แทนที่ %s ตัวที่ 3 ) );


สร้าง UPDATE query โดยใช้การแทนที่แบบกำหนดชื่อ (ไม่ต้องเรียงลำดับ)
$mysql->query( " UPDATE `games` SET `released` = %s[RELEASED], `title` = %s[TITLE], `price` = %s[PRICE] WHERE `id` = %s[ID] ", array( 'PRICE' => $_POST['price'], // แทนที่ %s[PRICE] 'TITLE' => $_POST['title'], // แทนที่ %s[TITLE] 'ID' => $_POST['id'], // แทนที่ %s[ID] 'RELEASED' => $_POST['released'], // แทนที่ %s[RELEASED] ) );


สร้าง SELECT query โดยใช้การแทนที่แบบผสม
$rows = $mysql->queryAndFetchAll( " SELECT %q, %q, %q FROM `games` WHERE `released` > %s[RELEASED] LIMIT %n[LIMIT] ", array( 'RELEASED' => $_POST['released'], // แทนที่ %s[RELEASED] 'LIMIT' => $_POST['limit'], // แทนที่ %n[LIMIT] 'title', // แทนที่ %q ตัวที่ 1 'price', // แทนที่ %q ตัวที่ 2 'id', // แทนที่ %q ตัวที่ 3 ) );


ซึ่งรูปแบบของตัวแทนที่มีดังต่อไปนี้

%q
ทำให้ค่าที่นำมาแทนที่เป็น identifier เพื่อใช้เป็นชื่อฐานข้อมูล ชื่อตาราง หรือชื่อคอลัมน์ เพราะจะกลายเป็นสตริงที่ถูกครอบด้วย `
และยังมีลักษณะพิเศษคือ หากค่าที่ส่งมามี . อยู่ ก็จะแยกออกจากกันด้วย . ก่อนแล้วจึงครอบด้วย `
echo $mysql->replaceString("SELECT * FROM %q", 'mydb.table'); // SELECT * FROM `mydb`.`table` echo $mysql->replaceString("SELECT * FROM `games` ORDER BY %q", 'games.id'); // SELECT * FROM `games` ORDER BY `games`.`id`


%s
ทำให้ค่าที่นำมาแทนที่เป็นชนิดสตริงที่ผ่านการ escape และครอบด้วย '
echo $mysql->replaceString("SELECT %s", "Cookie's cat"); // SELECT 'Cookie\'s cat' echo $mysql->replaceString("SELECT %s", "Line 1 Line 2 Line 3"); // SELECT 'Line 1\nLine 2\nLine 3\n'


%n
ทำให้ค่าที่นำมาแทนที่เป็นชนิดตัวเลข หากไม่สามารถแปลงเป็นตัวเลขได้ จะกลายเป็น 0
echo $mysql->replaceString("SELECT %n", 1); // SELECT 1 echo $mysql->replaceString("SELECT %n", '555'); // SELECT 555 echo $mysql->replaceString("SELECT %n", 'Hello World'); // SELECT 0


%b
ทำให้ค่าที่นำมาแทนที่เป็นชนิด Boolean คือจะเป็น TRUE หรือ FALSE เท่านั้น
เช่น 1 จะกลายเป็น TRUE และ 0 จะกลายเป็น FALSE
echo $mysql->replaceString("SELECT %b", true); // SELECT TRUE echo $mysql->replaceString("SELECT %b", 'Hello World'); // SELECT TRUE echo $mysql->replaceString("SELECT %b", false); // SELECT FALSE echo $mysql->replaceString("SELECT %b", null); // SELECT FALSE


%%
ใส่ค่าที่ต้องการเข้าไปตรงๆ เลย โดยไม่มีการ escape ใดใดทั้งสิ้น ไม่แนะนำให้ใช้หากไม่จำเป็นจริงๆ
echo $mysql->replaceString("SELECT %% `table`", 'COUNT(*) FROM'); // SELECT COUNT(*) FROM `table`


%?n
สำหรับ %s, %n และ %b สามารถมี n ต่อท้ายได้ โดยมีความหมายว่า "สามารถเป็น NULL"

echo $mysql->replaceString("SELECT %s", 'Hello'); // SELECT 'Hello' echo $mysql->replaceString("SELECT %s", null); // SELECT '' echo $mysql->replaceString("SELECT %sn", null); // SELECT NULL


การสร้าง list สำหรับ VALUES หรือ IN (...) ก็สามารถทำได้โดยง่าย

หากตัวแปรที่ส่งไปเป็น array ก็จะเชื่อมค่าเหล่านั้นด้วย , ให้อัตโนมัติ

สร้าง SELECT query
$ids = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); echo $mysql->replaceString( "SELECT * FROM `games` WHERE `id` IN (%s)", array($ids) ); // SELECT * FROM `games` WHERE `id` IN ('1','2','3','4','5','6','7','8','9','10')


สร้าง INSERT query
$columns = array('title', 'price', 'released'); $values = array('Dragon Quest X', '2590', '2012-08-02'); $mysql->query( "INSERT INTO `games` (%q) VALUES (%s)", array($columns, $values) ); // INSERT INTO `games` (`title`,`price`,`released`) VALUES ('Dragon Quest X','2590','2012-08-02')



Properties


$charset
encoding ปัจจุบันของการเชื่อมต่อ

กำหนด charset ของการเชื่อมต่อให้เป็น UTF-8 เทียบเท่ากับการใช้ SET NAMES utf8
$mysql->charset = 'utf8';





$errorCode
$errorMessage

หมายเลขความผิดพลาด (error code) และข้อความแสดงความผิดพลาด (error message) ที่เกิดขึ้นล่าสุด

แต่เนื่องจาก MySQL_Connection จะ throw MySQL_Exception ออกมาเมื่อมีความผิดพลาดเกิดขึ้น
และจะทำให้โปรแกรมจบการทำงานหากไม่ได้ดักจับ Exception
property ดังกล่าวจึงไม่อาจจะสามารถเข้าถึงได้ เพราะโปรแกรมจะจบการทำงานลงเสียก่อน

ดังนั้นหากจะตรวจจับ error เอง ต้องใช้ try ... catch

ดักจับความผิดพลาด ป้องกันการจบการทำงาน
try { $mysql->query("SELECT * FROM order"); } catch (Exception $e) { echo $mysql->errorMessage; }


ซึ่งมีประโยชน์สำหรับการเขียน query ที่ปล่อยให้มีความผิดพลาดโดยตั้งใจ
เช่น INSERT ค่าที่อาจจะซ้ำกันลงในคอลัมน์ชนิด PRIMARY หรือ UNIQUE

INSERT id แบบสุ่ม หาก id ที่สุ่มได้มีอยู่แล้ว ก็จะ INSERT ไม่ได้ ให้ทำซ้ำจนกว่าจะได้ id ที่ไม่ซ้ำ
// สั่งให้ลูปไม่รู้จบ while (true) { try { // id สุ่มตั้งแต่ 100000 - 999999 $mysql->query( " INSERT INTO `users` (`id`, `username`, `password`) VALUES (100000 + ROUND(RAND() * 899999), %s, %s) ", array($_POST['username'], md5($_POST['password'])) ); } catch (MySQL_Exception $exception) { // หาก INSERT ไม่ได้ ก็จะมาตรงนี้ // ตรวจ mysql error code ว่าใช้ 1062 (Duplicate entry '???' for key ???) หรือไม่ if ($mysql->errorCode === 1062) { // หากใช่ ก็สั่งให้ไปเริ่มต้นหลัง while (true) { อีกครั้ง continue; } // แต่ถ้าไม่ใช่ แสดงว่าเป็น error อย่างอื่นที่ไม่คาดคิด // ให้โยน exception ออกมาตามปกติเพื่อ debug throw $exception; } // หาก INSERT ได้ ก็จะไม่มี exception จะมาตรงนี้ // สั่งให้ออกจากลูป break; }





ส่วน property อื่นๆ ที่ใช้บ่อยๆ ในการเขียนแบบเก่าเช่น mysql_affected_rows() หรือ mysql_insert_id()
นั้นไม่ได้รวมมาในนี้ครับ เพราะสามารถใช้ SQL แทนได้

ตัวแทน mysql_affected_rows()
// หากต้องการหาว่า มีกี่แถว ที่เปลี่ยนแปลงโดยคำสั่งประเภท UPDATE หรือ DELETE // เราสามารถใช้ ROW_COUNT() ได้ $mysql->query("DELETE * FROM `table`"); $num_deleted_rows = $mysql->queryValue("SELECT ROW_COUNT()");


ตัวแทน mysql_insert_id()
// หากต้องการหาว่า id แบบ auto_increment ของแถวล่าสุดที่ INSERT ไป คืออะไร // เราสามารถใช้ LAST_INSERT_ID() ได้ $mysql->query("INSERT INTO `table` VALUES ('Test')"); $id = $mysql->queryValue("SELECT LAST_INSERT_ID()");


ตัวแทน mysql_num_rows()
$result = $mysql->queryResult("SELECT * FROM `table`"); echo $result->numRows;

หรือ
$rows = $mysql->queryAndFetchAll("SELECT * FROM `table`"); echo count($rows);





บทความที่เกี่ยวข้อง





ติดตามบทความล่าสุดของผู้เขียนได้ที่ phpinfo() Facebook Page







   
Share
Bookmark.   

  By : phpinfo()
  Article : บทความเป็นการเขียนโดยสมาชิก หากมีปัญหาเรื่องลิขสิทธิ์ กรุณาแจ้งให้ทาง webmaster ทราบด้วยครับ
  Score Rating :
  Create Date : 2013-06-02
  Download : No files
Sponsored Links
ThaiCreate.Com Forum


Comunity Forum Free Web Script
Jobs Freelance Free Uploads
Free Web Hosting Free Tools

สอน PHP ผ่าน Youtube ฟรี
สอน Android การเขียนโปรแกรม Android
สอน Windows Phone การเขียนโปรแกรม Windows Phone 7 และ 8
สอน iOS การเขียนโปรแกรม iPhone, iPad
สอน Java การเขียนโปรแกรม ภาษา Java
สอน Java GUI การเขียนโปรแกรม ภาษา Java GUI
สอน JSP การเขียนโปรแกรม ภาษา Java
สอน jQuery การเขียนโปรแกรม ภาษา jQuery
สอน .Net การเขียนโปรแกรม ภาษา .Net
Free Tutorial
สอน Google Maps Api
สอน Windows Service
สอน Entity Framework
สอน Android
สอน Java เขียน Java
Java GUI Swing
สอน JSP (Web App)
iOS (iPhone,iPad)
Windows Phone
Windows Azure
Windows Store
Laravel Framework
Yii PHP Framework
สอน jQuery
สอน jQuery กับ Ajax
สอน PHP OOP (Vdo)
Ajax Tutorials
SQL Tutorials
สอน SQL (Part 2)
JavaScript Tutorial
Javascript Tips
VBScript Tutorial
VBScript Validation
Microsoft Access
MySQL Tutorials
-- Stored Procedure
MariaDB Database
SQL Server Tutorial
SQL Server 2005
SQL Server 2008
SQL Server 2012
-- Stored Procedure
Oracle Database
-- Stored Procedure
SVN (Subversion)
แนวทางการทำ SEO
ปรับแต่งเว็บให้โหลดเร็ว


Hit Link
   







Load balance : Server 04
ThaiCreate.Com Logo
© www.ThaiCreate.Com. 2003-2024 All Rights Reserved.
ไทยครีเอทบริการ จัดทำดูแลแก้ไข Web Application ทุกรูปแบบ (PHP, .Net Application, VB.Net, C#)
[Conditions Privacy Statement] ติดต่อโฆษณา 081-987-6107 อัตราราคา คลิกที่นี่