×

คำเตือน

JFolder::create: Path not in open_basedir paths.

บทความนี้เป็นตอนต่อเนื่องจาก เขียนปลั๊กอินตรวจสอบผู้ใช้โดยใช้ฐานข้อมูล MSSQL ตอนที่ 1 นะครับหากท่านใดยังไม่ได้ได้อ่านบทความในตอนที่่แล้วขอให้อ่านก่อนนะครับ เพื่อจะได้ทำความเข้าใจได้ต่อเนื่อง จากตอนแรกเราบอกหลักการการทำงาน และขั้นตอนการพัฒนาปลั๊กอินกันไปแล้วในตอนนี้เราจะมาดูการเขียนโค้ดกัน แต่ก่อนที่จะเขียนโค้ดได้เราต้องมาสร้างไฟล์ XML สำหรับการติดตั้งกันก่อน เพื่อที่จะได้ทำการ Discover และติดตั้งให้จูมล่ารู้จัก เรามาดูกันเลยครับ

ไฟล์ mssql.xml สำหรับอธิบายการติดตั้ง

 ในส่วนของไฟล์ XML สำหรับให้จูมล่าใช้ในการติดตั้งมีรายละเอียดดังนี้ครับ

<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="authentication" method="upgrade">
	<name>Authentication - MSSQL Database</name>
  	<author>Prasit Gebsaap</author>
  	<creationDate>2014-06-10</creationDate>
  	<copyright>(C) 2011 by Prasit Gebsaap</copyright>
  	<license>http://www.gnu.org/licenses/gpl.html GNU/GPL</license>
  	<authorEmail>prasit.gebsaap-at-gmail.com</authorEmail>
  	<authorUrl>www.joomlant.org</authorUrl>
	<version>2.5.0 Beta2</version>
    <releaseDate>2011-01-13</releaseDate>
    <releaseType>Beta</releaseType>
	<description>PLG_AUTHENTICATION_MSSQL_XML_DESC</description>
	<files>
		<filename plugin="mssql">mssql.php</filename>
        <filename>index.html</filename>
        <folder>language</folder>
	</files>
    <config>
    	<fields name="params">
            <fieldset name="Basic">
          		<field name="dbserver" type="text" size="50" default="" label="PLG_AUTHENTICATION_MSSQL_DBHOST_LABEL" description="PLG_AUTHENTICATION_MSSQL_DBHOST_DESC" />
        		<field name="dbuser" type="text" size="50" default="" label="PLG_AUTHENTICATION_MSSQL_DBUSER_LABEL" description="PLG_AUTHENTICATION_MSSQL_DBUSER_DESC" />
        		<field name="dbpassword" type="text" size="50" default="" label="PLG_AUTHENTICATION_MSSQL_DBPASSWORD_LABEL" description="PLG_AUTHENTICATION_MSSQL_DBPASSWORD_DESC" />
        		<field name="dbname" type="text" size="50" default="" label="PLG_AUTHENTICATION_MSSQL_DBNAME_LABEL" description="PLG_AUTHENTICATION_MSSQL_DBNAME_DESC" />
                <field name="dbtable" type="text" size="50" default="" label="PLG_AUTHENTICATION_MSSQL_TABLENAME_LABEL" description="PLG_AUTHENTICATION_MSSQL_TABLENAME_DESC" />
        		<field name="loginfield" type="text" size="50" default="username" label="PLG_AUTHENTICATION_MSSQL_LOGINFIELD_LABEL" description="PLG_AUTHENTICATION_JOOMLANT_MSSQLAUTH_LOGINFIELD_DESC" />
        		<field name="passwordfield" type="text" size="50" default="password" label="PLG_AUTHENTICATION_MSSQL_PASSWORDFIELD_LABEL" description="PLG_AUTHENTICATION_MSSQL_PASSWORDFIELD_DESC" />
                <field name="emailfield" type="text" size="50" default="" label="PLG_AUTHENTICATION_MSSQL_EMAILFIELD_LABEL" description="PLG_AUTHENTICATION_MSSQL_EMAILFIELD_DESC"/>
                <field name="firstnamefield" type="text" size="50" default="" label="PLG_AUTHENTICATION_MSSQL_FIRSTNAMEFIELD_LABEL" description="PLG_AUTHENTICATION_MSSQL_FIRSTNAMEFIELD_DESC" />
                <field name="lastnamefield" type="text" size="50" default="" label="PLG_AUTHENTICATION_MSSQL_LASTNAMEFIELD_LABEL" description="PLG_AUTHENTICATION_MSSQL_LASTNAMEFIELD_DESC" />
            </fieldset>
    	</fields>
    </config>
</extension>
  • บรรทัดที่ 2 ในส่วนของ version ระบุเวอร์ชั่นของจูมล่าที่สามารถติดตั้งได้ type="plugin" เพื่อบอกว่าเป็นปลั๊กอิน และส่วนสำคัญคือ group="authentication"
  • บรรทัดที่ 3 - 13 จะเป็นส่วนของข้อมูลที่ใช้แสดงใน Extension Manager และ Plugin Manager เพื่อให้ข้อมูลแก่ผู้ใช้
  • บรรทัดที่ 14 - 18 เป็นการระบุไฟล์ที่มีในตัว Package สำหรับติดตั้ง ซึ่งเราจะมีไฟล์ mssql.php ไฟล์ mssql.xml คือไฟล์ที่เรากำลังพูดถึง และโฟลเดอร์สำหรับเก็บข้อมูลการแปลภาษา
  • บรรทัดที่่ 19 - 34 เป็นข้อมูลสำหรับการให้นิยามของการตั้งค่าของปลั๊กอิน โดยใช้รูปแบบของ JFORM ซึ่งเราจะให้ผู้ใช้กำหนดค่าข้อมูลต่างๆ เกี่ยวกับ ?Microsoft SQL Server ที่จะต้องเชื่่อมต่อจากจูมล่า

หลังจากดำเนินการตรงนี้เสร็จแล้ว คุณสามารถทำขั้นตอนของการ Discover โดยการ Purge Cache และกด Discover หลังจากที่จูมล่าแสดงรายการตัวปลั๊กอินขึ้นมา คุณสามารถคลิกเลือกหน้ารายการ แล้วกดปุ่ม Install เพื่อทำการติดตั้งได้เลยครับ หลังจากติดตั้งสำเร็จแล้วเรามาเปิดไฟล์ mssql.php เพื่อเขียนโค้ดกันต่อครับ

คลาส plgAuthenticationMssql

ในไฟล์ mssql.php เราจะสร้างคลาสของตัวปลัํ๊กอินของเราซึ่งสืบทอดมาจากคลาส JPlugin ของจูมล่าโดยการตั้งชื่อจะเป็น plgAuthenticationMssql โดยใช้หลักคือ คำสงวน plg ตามด้วยชื่อกลุ่ม และ ชื่่อปลักอินตามลำดับโดยสองตัวหลังให้ใช้อักษรตัวแรกเป็นตัวใหญ่ โดยตัวคลาส JPlugin จะเป็นคลาสแม่ที่ทำหน้าที่ส่วนใหญ่ให้เรา เช่นการโหลดไฟล์ภาษา การโหลดตัวแปรพารามีเตอร์ต่างๆ ที่กำหนดโดยผู้ใช้ให้เรา สิ่งที่เราต้องทำเพิ่มคือการเขียนเมธอท onAuthenticate() เพื่อทำการพิสูจน์ตัวตนผู้ใช้เมื่่อจูมล่าต้องการพิสูจน์ตัวตนของผู้ใช้โดยใช้ปลั๊กอินของเราครับ

เมธอท onAuthenticate()

สำหรับเมธอทหรือฟังก์ชั่น onAuthenticate() จะถูกเรียกใช้โดยจูมล่าเพื่อพิสูจน์ตัวตนของผู้ใช้ ในจูมล่า 3.1 จะมีตัวแปร $this->db ให้ใช้งานแต่เราไม่ได้ใช้ฐานข้อมูลของจูมล่าในการทำงาน เราจะต้องทำการสร้างการเชื่่อมต่อกับฐานข้อมูล Microsoft SQL ภายนอก แล้วจึงทำการ Query ข้อมูลผู้ใช้ที่อยู่บนฐานข้อมูลเพื่อเปรียบเทียบกับข้อมูลจากได้จากผู้ใช้ซึ่งถูกส่งมาให้ตัวแปรของฟังก์ชั่น onAuthenticate() ค่าพารามีเตอร์นี้มีดังนี้คือ

  • $credential เป็นข้อมูลแบบ array ที่มี 'username' และ 'password' ที่ผู้ใช้ทำการล็อกอิน
  • $options เป็นข้อมูล array ของตัวแปรทางเลือกอื่นๆ
  • $response เป็นตัวแปร Object ที่ตัวปลั๊กอินต้องกำหนดค่า เพื่อบอกจูมล่าถึงผลการตรวจสอบผู้ใช้ว่าสำเร็จหรือไม่ โดยกำหนดใน property ชื่อ status ในกณีที่ไม่สำเร็จก็ระบุเหตผลใน error_message ส่วนกรณีสำเร็จเราจะต้องส่งค่าอีเมลของผู้ใช้กลับด้วย ซึ่งจะใช้งานในกรณีที่ข้อมูลผู้ใช้ยังไม่ถูกสร้างในฐานข้อมูลของจูมล่ามันจะทำการสร้างข้อมูลนี้ให้โดยอัตโนมัติโดยเราไม่ต้องเสียเวลาในการไปสร้างรายการของผู้ใช้ก่อนนะครับ สำหรับคุณสมบัตินี้จะอยู่ในปลั๊กอินของจูมล่าในกลุ่ม user ชื่อ joomla ครับ ซึ่งปกติจะถูกเปิดไว้

การเชื่อมต่อฐานข้อมูลภายนอก

ปกติแล้วการเชื่อมต่อฐานข้อมูลของจูมล่าจะถูกสร้างโดยตัวจูมล่าเอง เราสามารถเรียกใช้งานได้โดยการเรียกผ่าน JFactory::getDbo() ซึ่งจะได้ตัว Object เดิมทุกครั้งเนื่องจากตัวพารามีเตอร์เหมือนเดิม คือค่าว่าง แต่เราสามารถสร้างการเชื่อมต่อใหม่ได้โดยเรียกผ่าน JDatabase::getInstance( $options) และส่งค่าพารามีเตอร์ที่ต้องใช้งาน เช่น ไอพี ชื่่อผู้ใช้ รหัสผ่าน ของเครื่่องแม่ข่ายที่ฐานข้อมูลนั้นๆ อยู่ และชื่อฐานข้อมูล แค่นี้เราก็จะได้ Object การเชื่อมต่อแล้ว หลังจากนั้นก็สามารถใช้ JDatabaseQuery ทำการ query ข้อมูลบนฐานข้อมูลนั้นๆ ได้เลย แค่ให้เป็นฐานข้อมูลที่จูมล่ามี Driver อยู่ก็พอครับ ในที่นี้เราใช้ MS SQL Server ซึ่งจูมล่ารองรับอยู่แล้ว แต่หากต้องการเปลี่ยนไปใช้ตัวอื่นๆ ก็แก้ไขไม่ยากครับ ข้อมูลในตัวแปร $options เป็นแบบ array ครับมีดังนี้

  • $options['driver'] = 'sqlsrv'
  • $options['database']  ชื่อฐานข้อมูล
  • $options['select'] = true
  • $options['host']
  • $options['user']
  • $options['password']

สำหรับรายละเอียดเหล่านี้เข้าไปดูในโฟลเดอร์

  • libraries/joomla/database/database/ สำหรับจูมล่า 2.5
  • ibraries/joomla/database/driver/ ส่วนจูมล่า 3.0 ขึ้นไป

แล้วก็เปิดดูไฟล์ที่ต้องการครับ นั่นคือ driver ของจูมล่าชื่อไฟล์คือชื่อตัวแปร $options['driver'] แล้วลองดูใน __construct ดูว่าตัวแปรที่ต้องใช้มีอะไรบ้าง

ไฟล์ mssql.php แบบเต็มรูปแบบ

// Check to ensure this file is included in Joomla!
defined( '_JEXEC' ) or die;

// Import library dependencies
jimport('joomla.plugin.plugin');
 
class plgAuthenticationMssql extends JPlugin
{    
    /**
     * This method should handle any authentication and report back to the subject
     * This example uses simple authentication - it checks if the password is the reverse
     * of the username (and the user exists in the database).
     *
     * @access    public
     * @param     array     $credentials    Array holding the user credentials ('username' and 'password')
     * @param     array     $options        Array of extra options
     * @param     object    $response       Authentication response object
     * @return    boolean
     * @since 1.5
     */
    function onUserAuthenticate( $credentials, $options, &$response )
    {
    	$options = array();
    	$options['driver']		= 'sqlsrv';
        $options['host'] 		= $this->params->get('dbserver');
        $options['user'] 		= $this->params->get('dbuser');
        $options['password'] 	= $this->params->get('dbpassword'); 
       
        $options['database'] 	= $this->params->get('dbname');
        $options['select'] 		= true;
        
        $dbtable = $this->params->get('dbtable');
        $loginfield = $this->params->get('loginfield');
        $passwordfield = $this->params->get('passwordfield');
        $emailfield = $this->params->get('emailfield');
        $firstnamefield = $this->params->get('firstnamefield');
        $lastnamefield = $this->params->get('lastnamefield');
        
        $sqlDbo = JDatabase::getInstance($options);

        if (!$sqlDbo) {
            $response->status = JAUTHENTICATE_STATUS_FAILURE;
            $response->error_message = 'Cannot connect to MSSQL Database Server.';
            return false; //die('Something went wrong while connecting to MSSQL');
        }
        $query = $sqlDbo->getQuery(true);
        $query->select('*')
        	->from($dbtable)
        	->where($loginfield. '=' . $sqlDbo->quote($credentials['username']));
		$sqlDbo->setQuery($query);
		$userRec = $sqlDbo->loadObject();
        if (!$userRec){
            $response->status = JAuthentication::STATUS_FAILURE;
            $response->error_message = 'No record in database.';
            return false;
        }
 
        // to authenticate, the username must exist in the database, and the password should be equal
        if ($credentials['password'] ==  $userRec->$passwordfield )
        {
            if (!empty($firstnamefield)){
                $fullname = $userRec->$firstnamefield;
            }
            if (!empty($lastnamefield)){
                $fullname .= ' '.$userRec->$lastnamefield;
            }
            
            $response->type = 'Joomlant_mssqlauth';

            $response->email = $userRec->$emailfield;   
            $response->fullname = $fullname;
            $response->username = $credentials['username'];
            $response->password_clear = $credentials['password'];

            $response->status = JAuthentication::STATUS_SUCCESS;
            return true;
        }
        else
        {
            $response->status = JAuthentication::STATUS_FAILURE;
            $response->error_message = 'Invalid username and password';
            return false;
        }
    }
  
}

 ลองดูคร่าวๆ นะครับ หากว่าเราทำการ Query ไม่ได้ หรือไม่สามารถหาข้อมูลผู้ใช้งานตามข้อมูลที่ได้รับ เราต้องส่งค่า FALSE กลับไป ในทางตรงกันข้ามเราต้องส่่งสถานะของการตรวจสอบ และสาเหตุด้วย นอกจากนี้เรายังต้องกำหนดค่าต่างๆ ใน $response เพื่อให้จูมล่านำไปใช้งานต่อได้

comments