Tag Archive Extension

Byphunsanit

PowerBuilder: file extension

ในส่วนของ source code ของ PowerBuilder ประกอบด้วยไฟล์นามสกุลต่าง ๆ

ความหมายfile extension
Application source files.sra
Custom user object source files.sru
Data pipeline source files.srp
DataWindow source files.srd
Dynamic link library files.pdb
Function source files.srf
Library files.pbl
Menu source files.srm
Project files.srj
Query source files.srq
Structure source files.srs
Target files.pbt
Window source files.srw
Workspace files.pbw
Byphunsanit

การติดตั้ง PHP บน IIS

มีความจำเป็นบางอย่างที่ทำให้ต้องลง PHP ใน Internet Information Services (IIS) แทน apache / xampp ตามปกติ แต่จริงๆ แล้วมันก็ไม่ได้ติดตั้งยากอะไร แค่มีวิธีการที่ต่างไปจากปกติเท่านั้นเอง

ขั้นตอนการติดตั้้ง

  1. download Web Platform Installer มาติดตั้งก่อน
  2. เปิดโปรแกรม Microsoft Web Platform Installer
  3. มุมขวาบนจะมีช่องให้ search หาส่วนติดตั้งที่ต้องการ เช่น PHP 7.4 โดยมีเคล็ดลับคือ ถ้าต้องลง sql server driver ด้วยให้หา Microsoft Drivers for PHP ที่มี version สูงมากที่สุดก่อน เพราะบางครั้งมี PHP version ใหม่มาแล้วแต่ไม่มี sql driver ให้เลือก เมื่อได้ที่ต้องการแล้วให้คลิก add ไว้ก่อน จากนั้นก็ไปหาส่วนที่ต้องการอื่น ๆ ต่อไปเช่น Web Platform Installer ต้องใช้ในการ rewrite url ใน iis
  4. เมื่อได้ครบแล้วคลิก Install
  5. คลิก I Accept
  6. ปิดโปรแกรมเมื่อไม่ต้องการติดตั้งเพิ่มเติมแล้ว

php จะถูกติดตั้งอยู่ใน C:\Program Files\PHP แยกตาม php version เช่น v7.3 โดยจะมี php.ini และ extension ต่างๆ แยกออกมาต่างหาก โดยในบรรทัดล่าง ๆ จะมี [PHP_WINCACHE] หรือ [ExtensionList] บอกตำแหน่งที่เกี่ยวกับ php / zend entension ที่ได้ถูกติดตั้งเอาไว้

Byphunsanit

ติดตั้ง imagick ImageMagick ใน windows (xampp)

การติดตั้ง imagick (ImageMagick) มันจะมีขั้นตอนพิเศษคือ copy .dll นอกจาก php_imagick.dll ใส่ไว้ใน apache\bin และต้องเซ็ต ENVIRONMENT PATH ด้วย

ขั้นตอนการติดตั้งแบบละเอียด

  1. เปิด phpinfo ดู PHP Version ของ server ที่ต้องการจะติดตั้ง
  2. เปิด PECL: imagick download สังเกต สัญลักษณ์ windows คลิกไปจะบอกว่า version นี้สามารถใช้กับ php version ไหนได้บ้าง ลองไล่จาก version ใหม่ล่าสุดลงมาของใหม่ยังไงก็ดีกว่าของเก่าๆ จากนั้นเลือกไฟล์จากข้อมูลใน phpinfo
    Thread Safety
    disabled
    แทนด้วย NTS
    enabled
    แทนด้วย TS
    Architecture
    เป็น x64 หรือ x86

    เช่น 7.1 Thread Safe (TS) x64 คือ php version = 7.1 Thread Safety = enable Architecture = x64 คลิกโหลดมาจะได้ไฟล์ php_imagick-3.4.3-7.1-ts-vc14-x86.zip

  3. แตกไฟล์ที่โหลดมาให้ php_imagick.dll ไปที่ folder extension_dir ใน phpinfo (เช่น C:\xampp\php\ext)
  4. แตกไฟล์นามสกุล .dll ที่เหลือไปที่ apache/bin (เช่น C:/xampp/apache/bin)
  5. เปิดไฟล์ php.ini ขึ้นมา โดยดูจาก Loaded Configuration File ใน phpinfo (เช่น C:\xampp\php\php.ini) เพิ่ม
    ...
    extension=php_imagick.dll
    ...
  6. โหลดตัวโปรแกรม ImageMagick มาจาก Windows Binary Release เลือก version ที่ต้องการโดย
    Q
    คือ bits-per-pixel มีให้เลือก 8 กับ 16 ยิ่งเยอะภาพจะยิ่งชัดแต่ตัวไฟล์จะใหญ่กว่า
    x86 / x64
    คือ Architecture ของ windows ที่ใช้อยู่ เลือกให้ตรงกับเครื่อง server ถ้าไม่ได้ใช้ Windows 32-bit ใช้ x64 จะดีกว่า

    โหลดแล้วติดตั้งตามปกติ อย่าลืมติ๊ก Add application directory to your system path

  7. restart apache จากนั้น ค้นหา imagick ถ้าขึ้นแสดงว่าติดตั้งสำเร็จ และดู PATH จะมี folder ที่ติดตั้ง Magick เช่น C:\Program Files\ImageMagick-7.0.5-Q16; Image ไว้ (ถ้าไม่มีลอง restart windows ดู)
Byphunsanit

CodeIgniter: php-amqplib

ลองเขียน custom driver สำหรับติดต่อกับ RabbitMQ / AMQP ยังไม่สมบูรณ์แต่ก็ดีกว่าการที่ต้องมา connect ผ่าน php-amqplib ทุกครั้งที่จะใช้ตามปกติ

  1. config file ก่อนตามระเบียบ
    <?php
    defined('BASEPATH') or exit('No direct script access allowed');
    
    /*
    | -------------------------------------------------------------------
    | RABBITMQ CONNECTIVITY SETTINGS
    | -------------------------------------------------------------------
    | This file will contain the settings needed to access your RabbitMQ.
    |
    | For complete instructions please consult the 'RabbitMQ Connection'
    | page of the User Guide.
    |
    | -------------------------------------------------------------------
    | EXPLANATION OF VARIABLES
    | -------------------------------------------------------------------
    |
    |    ['connection_timeout'] => 3.0,
    |    ['context'] => null,
    |    ['heartbeat'] => 0
    |    ['host'],
    |    ['insist'] => false,
    |    ['keepalive'] => false,
    |    ['locale'] => 'en_US',
    |    ['login_method'] => 'AMQPLAIN',
    |    ['login_response'] => null,
    |    ['password'],
    |    ['port'],
    |    ['read_write_timeout'] => 3.0,
    |    ['user'],
    |    ['vhost'] => '/',
     */
    $config['RabbitMQ']['connects'] = [
        'default' => [
            'connection_timeout' => 3.0,
            'context' => null,
            'heartbeat' => 0,
            'host' => '127.0.0.1',
            'insist' => false,
            'keepalive' => false,
            'locale' => 'en_US',
            'login_method' => 'AMQPLAIN',
            'login_response' => null,
            'password' => 'guest',
            'port' => 5672,
            'read_write_timeout' => 3.0,
            'user' => 'guest',
            'vhost' => '/',
        ],
    ];
    
    /*
    | -------------------------------------------------------------------
    | RABBITMQ DEBUG SETTINGS
    | -------------------------------------------------------------------
    |
     */
    $config['RabbitMQ']['debug'] = false;
    
  2. ถึงคิวไฟล์ driver ที่จะเป็นตัวกลางระหว่าง codeigniter และ php-amqplib
    <?php
    use PhpAmqpLib\Connection\AMQPStreamConnection;
    use PhpAmqpLib\Message\AMQPMessage;
    
    class RabbitMQ extends AMQPStreamConnection
    {
    
        public function __construct($config = array())
        {
            $this->CI = &get_instance();
    
            $this->config = $config['RabbitMQ'];
    
            if ($this->config['debug'] == true) {
                define('AMQP_DEBUG', true);
            }
        }
    
        public function connect($dsnId = 'default') {
            $dsn = $this->config['connects'][$dsnId];
    
            $this->connection = new AMQPStreamConnection($dsn['host'], $dsn['port'], $dsn['user'], $dsn['password'], $dsn['vhost'], $dsn['insist'], $dsn['login_method'], $dsn['login_response'], $dsn['locale'], $dsn['connection_timeout'], $dsn['read_write_timeout'], $dsn['context'], $dsn['keepalive'], $dsn['heartbeat']);
    
            $this->channel = $this->connection->channel();
        }
    
        public function disconnect()
        {
            $this->channel->close();
            $this->connection->close();
        }
    
        public function setMessageJson($datas)
        {
            $msg_body = json_encode($datas);
    
            $properties = [
                'content_type' => 'application/json',
                'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
            ];
    
            return new AMQPMessage($msg_body, $properties);
        }
    
    }
  3. ที่นี้ก็ controller ที่จะทำงานให้
    <?php
    defined('BASEPATH') or exit('No direct script access allowed');
    
    class Messaging extends CI_Controller
    {
        public function __construct()
        {
            parent::__construct();
    
            $this->load->driver('RabbitMQ');
        }
    
        public function receive()
        {
            set_time_limit(0);
    
            $this->rabbitmq->connect();
    
            $exchange_name = 'customers';
            $queue_name = 'invoices';
    
    /**
     * Declares exchange
     *
     * @param string $exchange_name
     * @param string $type
     * @param bool $passive
     * @param bool $durable
     * @param bool $auto_delete
     * @param bool $internal
     * @param bool $nowait
     * @param array $arguments
     * @param int $ticket
     * @return mixed|null
     */
            $this->rabbitmq->channel->exchange_declare($exchange_name, 'fanout', false, true, false);
    
    /**
     * Declares queue, creates if needed
     *
     * @param string $queue
     * @param bool $passive
     * @param bool $durable
     * @param bool $exclusive
     * @param bool $auto_delete
     * @param bool $nowait
     * @param array $arguments
     * @param int $ticket
     * @return mixed|null
     */
            list($queueName, $message_count, $consumer_count) = $this->rabbitmq->channel->queue_declare('', false, false, true, false);
            $this->rabbitmq->channel->queue_bind($queue_name, $exchange_name);
    
            $callback = function ($msg) {
    
                $datas = json_decode($msg->body, true);
                fwrite(fopen('RabbitMQReceive.txt', 'a+'), print_r($datas, true));
    
                sleep(substr_count($msg->body, '.'));
    
                /* delete message */
                $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
            };
    
    /**
     * Starts a queue consumer
     *
     * @param string $queue_name
     * @param string $consumer_tag
     * @param bool $no_local
     * @param bool $no_ack
     * @param bool $exclusive
     * @param bool $nowait
     * @param callback|null $callback
     * @param int|null $ticket
     * @param array $arguments
     * @return mixed|string
     */
            $this->rabbitmq->channel->basic_consume($queue_name, '', false, false, false, false, $callback);
    
            while (count($this->rabbitmq->channel->callbacks)) {
    /**
     * Wait for some expected AMQP methods and dispatch to them.
     * Unexpected methods are queued up for later calls to this PHP
     * method.
     *
     * @param array $allowed_methods
     * @param bool $non_blocking
     * @param int $timeout
     * @throws \PhpAmqpLib\Exception\AMQPOutOfBoundsException
     * @throws \PhpAmqpLib\Exception\AMQPRuntimeException
     * @return mixed
     */
                $this->rabbitmq->channel->wait();
            }
    
            $this->rabbitmq->channel->close();
            $connection->close();
        }
    
        public function send()
        {
            $this->rabbitmq->connect();
    
            $exchange_name = 'customers';
            $queue_name = 'invoices';
    
    /**
     * Declares exchange
     *
     * @param string $exchange_name
     * @param string $type
     * @param bool $passive
     * @param bool $durable
     * @param bool $auto_delete
     * @param bool $internal
     * @param bool $nowait
     * @param array $arguments
     * @param int $ticket
     * @return mixed|null
     */
            $this->rabbitmq->channel->exchange_declare($exchange_name, 'fanout', false, true, false);
    
    /**
     * Declares queue, creates if needed
     *
     * @param string $queue
     * @param bool $passive
     * @param bool $durable
     * @param bool $exclusive
     * @param bool $auto_delete
     * @param bool $nowait
     * @param array $arguments
     * @param int $ticket
     * @return mixed|null
     */
            list($queueName, $message_count, $consumer_count) = $this->rabbitmq->channel->queue_declare($queue_name, false, true, false, false);
    
            $datas = [
                'rand' => rand(0, 100),
                'time' => date('Y-m-d H:m:s'),
            ];
    
    /**
     * Declares message
     *
     * @param array $datas
     * @return string
     */
            $msg = $this->rabbitmq->setMessageJson($datas);
    
    /**
     * Publishes a message
     *
     * @param AMQPMessage $msg
     * @param string $exchange
     * @param string $routing_key
     * @param bool $mandatory
     * @param bool $immediate
     * @param int $ticket
     */
            $this->rabbitmq->channel->basic_publish($msg, $exchange_name, $queue_name);
    
            echo '<br><pre>' . print_r($datas, true), '</pre>';
    
            $this->rabbitmq->disconnect();
    
        }
    
    }
    
  4. ทดสอบโดยเรียก http://localhost/CodeIgniter-3.1.3/messaging/send และ http://localhost/CodeIgniter-3.1.3/messaging/receive
Byphunsanit

PHP: php-amqplib แบบต่อเนื่อง

ในบาง page เราอาจจะต้องการที่จะใช้ queuing หลายตัว แทนที่จะ connect / disconnect หลายๆครั้ง เราสามารถใช้ batch / bulk ในการส่งช้อมูลให้ rabbitmq ในครั้งเดียวได้

<?php

include 'RabbitMQConnection.php';

use PhpAmqpLib\Message\AMQPMessage;

$exchange_name = 'customers';
$queue_name = 'invoices';

/**
 * Declares exchange
 *
 * @param string $exchange_name
 * @param string $type
 * @param bool $passive
 * @param bool $durable
 * @param bool $auto_delete
 * @param bool $internal
 * @param bool $nowait
 * @param array $arguments
 * @param int $ticket
 * @return mixed|null
 */
$channel->exchange_declare($exchange_name, 'fanout', false, true, false);

/**
 * Declares queue, creates if needed
 *
 * @param string $queue
 * @param bool $passive
 * @param bool $durable
 * @param bool $exclusive
 * @param bool $auto_delete
 * @param bool $nowait
 * @param array $arguments
 * @param int $ticket
 * @return mixed|null
 */
 list($queueName, $message_count, $consumer_count) = $channel->queue_declare($queue_name, false, true, false, false);

$properties = [
    'content_type' => 'application/json',
    'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
];

for ($a = 1; $a <= 1000; $a++) {
    $datas = [
        'id' => str_pad($a, 4, '0', STR_PAD_LEFT),
        'rand' => rand(0, 100),
        'time' => date('Y-m-d H:m:s'),
    ];

	$msg_body = json_encode($datas);

	$msg = new AMQPMessage($msg_body, $properties);

	/**
	 * Publishes a message
	 *
	 * @param AMQPMessage $msg
	 * @param string $exchange
	 * @param string $routing_key
	 * @param bool $mandatory
	 * @param bool $immediate
	 * @param int $ticket
	 */
	$channel->basic_publish($msg, $exchange_name, $queue_name);

    /**
     * Publishes a message
     *
     * @param AMQPMessage $msg
     * @param string $exchange
     * @param string $routing_key
     * @param bool $mandatory
     * @param bool $immediate
     * @param int $ticket
     */
    $channel->basic_publish($msg, $exchange_name, $queue_name);

    echo '<br>' . $msg_body;
}

/**
 * Publish batch
 *
 * @return void
 */
$channel->publish_batch();

$channel->close();
$connection->close();

อ่านเพิ่มเติม

Byphunsanit

PHP: ใช้ RabbitMQ / AMQP โดย php-amqplib

ถึงจะติดตั้ง extension amqp ไว้แล้วก็จริงแต่เพราะว่าการติดตั้งอะไรเพิ่มให้ระบบเซิร์ฟเวอร์บริษัทจำเป็นต้องมีการขออนุมัติจากคณะกรรมการซะก่อน เพื่อความสดวกจึงใช้ php-amqplib/php-amqplib แทนโดยสามารถติดตั้งได้โดยใช้ composer ได้เลย

สร้างส่วน connect กับ RabbitMQ ก่อน

<?php

/* define('AMQP_DEBUG', true); */

require_once __DIR__ . '/vendor/autoload.php';

use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

ค่าคงที่ define(‘AMQP_DEBUG’, true); ใช้เปิด debug mode ของตัว class php-amqplib

การส่งข้อมูล

<?php

include 'RabbitMQConnection.php';

use PhpAmqpLib\Message\AMQPMessage;

$exchange_name = 'customers';
$queue_name = 'invoices';

/**
 * Declares exchange
 *
 * @param string $exchange_name
 * @param string $type
 * @param bool $passive
 * @param bool $durable
 * @param bool $auto_delete
 * @param bool $internal
 * @param bool $nowait
 * @param array $arguments
 * @param int $ticket
 * @return mixed|null
 */
$channel->exchange_declare($exchange_name, 'fanout', false, true, false);

/**
 * Declares queue, creates if needed
 *
 * @param string $queue
 * @param bool $passive
 * @param bool $durable
 * @param bool $exclusive
 * @param bool $auto_delete
 * @param bool $nowait
 * @param array $arguments
 * @param int $ticket
 * @return mixed|null
 */
list($queueName, $message_count, $consumer_count) = $channel->queue_declare($queue_name, false, true, false, false);

$datas = [
    'rand' => rand(0, 100),
    'time' => date('Y-m-d H:m:s'),
];

$msg_body = json_encode($datas);

$properties = [
    'content_type' => 'application/json',
    'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT,
];

$msg = new AMQPMessage($msg_body, $properties);

/**
 * Publishes a message
 *
 * @param AMQPMessage $msg
 * @param string $exchange
 * @param string $routing_key
 * @param bool $mandatory
 * @param bool $immediate
 * @param int $ticket
 */
$channel->basic_publish($msg, $exchange_name, $queue_name);

echo '<br>' . $msg_body;

$channel->close();
$connection->close();

จากนั้นรับ message

<?php

include 'RabbitMQConnection.php';

set_time_limit(0);

$exchange_name = 'customers';
$queue_name = 'invoices';

/**
 * Declares exchange
 *
 * @param string $exchange_name
 * @param string $type
 * @param bool $passive
 * @param bool $durable
 * @param bool $auto_delete
 * @param bool $internal
 * @param bool $nowait
 * @param array $arguments
 * @param int $ticket
 * @return mixed|null
 */
$channel->exchange_declare($exchange_name, 'fanout', false, true, false);

/**
 * Declares queue, creates if needed
 *
 * @param string $queue
 * @param bool $passive
 * @param bool $durable
 * @param bool $exclusive
 * @param bool $auto_delete
 * @param bool $nowait
 * @param array $arguments
 * @param int $ticket
 * @return mixed|null
 */
list($queueName, $message_count, $consumer_count) = $channel->queue_declare('', false, false, true, false);
$channel->queue_bind($queue_name, $exchange_name);

$callback = function ($msg) {

    $datas = json_decode($msg->body, true);
    fwrite(fopen('RabbitMQReceive.txt', 'a+'), print_r($datas, true));

    sleep(substr_count($msg->body, '.'));

    /* delete message */
    $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};

/**
 * Starts a queue consumer
 *
 * @param string $queue_name
 * @param string $consumer_tag
 * @param bool $no_local
 * @param bool $no_ack
 * @param bool $exclusive
 * @param bool $nowait
 * @param callback|null $callback
 * @param int|null $ticket
 * @param array $arguments
 * @return mixed|string
 */
$channel->basic_consume($queue_name, '', false, false, false, false, $callback);

while (count($channel->callbacks)) {
    /**
     * Wait for some expected AMQP methods and dispatch to them.
     * Unexpected methods are queued up for later calls to this PHP
     * method.
     *
     * @param array $allowed_methods
     * @param bool $non_blocking
     * @param int $timeout
     * @throws \PhpAmqpLib\Exception\AMQPOutOfBoundsException
     * @throws \PhpAmqpLib\Exception\AMQPRuntimeException
     * @return mixed
     */

    $channel->wait();
}

$channel->close();
$connection->close();

ข้อมูลจะถูกดำเนินการโดย function callback .ในตัวอย่างจะถูกเขียนไว้ใน RabbitMQReceive.txt และถูกลบออกไปโดย การกำหนดค่าให้ delivery_info

หลักการการทำงานคือ

  1. ย้าย process ที่ไม่ต้องทำทันทีไปทำงานทีหลังโดยใช้ การส่ง ตัวแปรที่จำเป็นไปในรูปแบบ message ให้ rabbitmq ทำให้ user ไม่จำเป็นต้องรอและรู้สึกว่าเว็บทำงานให้อย่างรวดเร็ว
  2. message จะถูกเก็บใน queue ที่ชื่อ “invoices”
  3. เมื่อ server ว่าง ก็เรียก message ใน queue ที่เก็บไว้ ดึงข้อมูลออกมา เพื่อนำไปทำงานต่อไป

อ่านเพิ่มเติม

Byphunsanit

PHP: ติดตั้ง RabbitMQ / AMQP Driver

ที่ทำงานนำ RabbitMQ มาทำระบบ messaging middleware เพื่อที่จะไม่ต้องให้ลูกค้ารอการทำงานเบื้องหลังบางอย่าง โดยเก็บงานที่ไม่เร่งด่วนไว้ทำในภายหลัง

ตัว RabbitMQ เป็นหนึ่งในโปรแกรม Messaging ที่ใช้มาตราฐาน AMQP: Advanced Message Queuing Protocol หรือ ISO/IEC 19464:2014 โปรแกรมตัวอื่นๆ เช่น Apache Qpid และ OpenAMQP

การติดตั้ง

  1. download ตัว driver มาจากเว็บ PECL: amqp โดยเลือกให้ตรงกับ version ของ php
  2. แตกไฟล์ php_amqp.dll ไปไว้ที่ extension_dir เช่น C:\wamp64\bin\php\php5.6.25\ext
  3. แตกไฟล์ rabbitmq.1.dllไปไว้ที่ C:\Windows\System ระวัง! ไม่ใช่ System32 นะครับ
  4. แก้ไฟล์ C:\wamp64\bin\apache\apache2.4.23\bin\php.ini เพิ่ม extension=php_amqp.dll
  5. restart apache ใหม่
  6. เปิด phpinfo ขึ้นมาหา amqp ถ้ามีก็แสดงว่าติดตั้ง extension amqp สำเร็จ

อ่านเพิ่มเติม

Byphunsanit

เชื่อมต่อพีเฮชพีกับ sql server (sqlsrv)

ถึง mysql จะฟรี ดี รับงานหนักๆ ได้ แต่องค์กรหรือบริษัทใหญ่ๆจะเชื่อถือ microsoft sql server มากกว่าคู่บารมี คู่แท้ php & mysql วันนี้เราจะมาทำให้ php connect กับเอสคิวแอล เซิร์ฟเวอร์กัน โดยใช้ driver ตัวใหม่ sqlsrv แทน mssql ที่โดนยกเลิกไป

  1. เช็ค version ของ php ก่อนโดย run command php -v
  2. download Microsoft Drivers for PHP for SQL Server จากเว็บ http://www.microsoft.com โดยตรง เลือก version ให้ตรงกับ php ที่เราใช้
  3. เปิด ตัว driver ขึ้นมา
    • กด yes ยอมรับข้อตกลงซะ คุณจะได้ไปต่อ
    • เลือกโพลเดอร์ที่จะแตกไฟล์ชั่วคราว ยังไม่ใช่ที่ๆ จะติดตั้งโปรแกรมจริง ๆ
    • หลังจาก สร้างไฟล์ใน folder ที่เราเลือกเสร็จแล้วจะมี alert ขึ้นมา แล้วมันจะปิดตัวเองไม่ต้องตกใจ
  4. เข้าไปดูโฟลเดอร์ที่เลือกไว้ จะเห็นไฟล์ เยอะแยะเลย หาไฟล์ที่เลขตรงกับเวอร์ชั่นเดียวกับ php ของเรา เช่น ใช้ php 5.6 ก็เลือกไฟล์ _56 จะเห็นว่ามี 4 ไฟล์ จะสังเกตุว่า มี _nts และ _ts ความหมายก็คือ
    _nts
    ย่อมาจาก Non Thread Safe สำหรับ php ที่ลงแบบ CGI binary
    _ts
    ย่อมาจาก Thread Safe สำหรับ php ที่ลงแบบ Apache module ถ้าใช้ xampp จะใช้ตัวนี้
  5. เปิดโฟลเดอร์เอ็กเท็นชั่นของพีเอชพี xampp จะอยู่ที่ C:\xampp\php\ext คัดลอกไฟล์ที่เราเลือกมา (แค่ 2 ไฟล์) มาวางเพิ่มเข้าไป
  6. เปิดไฟล์ php.ini xampp อยู่ที่ C:\xampp\php\php.ini ค้นหาบรรทัดที่มี extension=
    แล้วเพิ่ม config ไปตามตัวอย่าง

    extension=php_sqlsrv_56_ts.dll
    extension=php_pdo_sqlsrv_56_ts.dll
    
  7. ถ้าลง sql server ในเครื่องเดียวกับ apache ให้ไปปิด service “SQL Server Reporting Services” ก่อน และเปลี่ยน startup type เป็น manual ก่อนเพราะมันใช้ port 80 เหมือนเว็บเซิร์ฟเวอร์ เป็นสาเหตุที่ทำให้ apache start service ไม่ได้
  8. restart apache ไปดู phpinfo ถ้ามี pdo_sqlsrv และ sqlsrv ขึ้นมาก็แสดงว่าลงเอสคิวแอล เซิร์ฟเวอร์ไดร์เวอร์สำเร็จ
Byphunsanit

พรีวิวรูปที่อัพโหลด

ถ้าเวลาเรา upload รูปขึ้น server คงจะดีถ้าเราเห็นว่าเราเลือกภาพถูกรึเปล่า หรือขนาดมันใหญ่เกินไปมั๋ย เราทำได้โดยการแสดงภาพ Preview ขนาด ความกว้าง ความสูง และทำการตรวจสอบก่อนจะได้ไม่เสียเวลา

ตัวอย่าง jQuery Upload Image Preview Demo

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>jQuery Upload Image Preview</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
	<label>เฉพาะรูปภาพ
		<input type="file" name="pic" accept="image/*">
	</label>
</form>
<img id="picPreview">
<dl>
	<dt>image dimensions width</dt>
	<dd id="picDimensionsWidth"></dd>
	<dt>image dimensions height</dt>
	<dd id="picDimensionsHeight"></dd>
	<dt>lastModified</dt>
	<dd id="picLastModified"></dd>
	<dt>lastModifiedDate</dt>
	<dd id="picLastModifiedDate"></dd>
	<dt>name</dt>
	<dd id="picName"></dd>
	<dt>original file upload path</dt>
	<dd id="picPath"></dd>
	<dt>size</dt>
	<dd id="picSize"></dd>
	<dt>type</dt>
	<dd id="picType"></dd>
</dl>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script>
$('[name="pic"]').change(function(){

	/* original file upload path */
	$('#picPath').text($(this).val());

	var file = this.files[0];
	/* get picture details */
	$('#picLastModified').text(file.lastModified);
	$('#picLastModifiedDate').text(file.lastModifiedDate);
	$('#picName').text(file.name);
	$('#picSize').text(file.size);
	$('#picType').text(file.type);

	/* set image preview */
	if( ! file.type.match(/image.*/))
	{
		return true;
	}
	var reader = new FileReader();
	reader.onload = function (event)
	{
		$('#picPreview').attr('src', event.target.result);

		/* get image dimensions */
		var image = new Image();
		image.src = reader.result;
		image.onload = function()
		{
			$('#picDimensionsWidth').text(image.width);
			$('#picDimensionsHeight').text(image.height);
		};

	}
	reader.readAsDataURL(file);

});
</script>
</body>
</html>
Byphunsanit

เลือกชนิดไฟล์อัพโหลด

คุณสมบัติที่น่าสนใจอย่างหนึ่งของ HTML 5 คือเราสามารถกำหนดให้อินพุทยอมรับชนิดไฟล์ตามที่เราต้องการได้ ช่องใส่ภาพประจำตัว ก็น่าจะใส่ได้แค่นามสกุล jpeg อย่างน้อยก็ png หรือ gif แต่ก็มียูเซอร์ copy รูปใส่ word upload เข้ามา สมกับ used เซ่อๆ จริงๆ
เราสามารถกำหนดได้โดยใช้ accept Attribute ตามตัวอย่าง

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>HTML5 Form Input Accept</title>
<style>
label
{
	display: block;
}
</style>
</head>
<body>
<form action="" enctype="multipart/form-data">
	<label>เฉพาะไฟล์เสียง
		<input type="file" name="files[]" accept="audio/*">
	</label>
	<label>เฉพาะรูปภาพ
		<input type="file" name="files[]" accept="image/*">
	</label>
	<label>เฉพาะวีดีโอ
		<input type="file" name="files[]" accept="video/*">
	</label>
	<label>pdf
		<input type="file" name="files[]" accept="application/pdf">
	</label>
	<label>.gif หรือ .png
		<input type="file" name="files[]" accept="image/gif, image/png">
	</label>
	<label>.jpg
		<input type="file" name="files[]" accept="image/pjpeg, image/jpeg">
	</label>
	<input type="submit">
</form>
</body>
</html>

จะสังเกตุว่าเวลาเรา browse file มันจะแสดงเฉพาะนามสกุลที่เรากำหนด แต่ยังเปลี่ยนตัวเลือกไปเป็น All Files (*.*) ได้อยู่ดี มันแค่ช่วยให้เลือกไฟล์ได้ง่ายขึ้น ยังรับประกันไม่ได้อยู่ดีว่าจะได้นามสกุลไฟล์ที่ถูกต้อง หรือไฟล์ที่ส่งมานามสกุลถูกตาม Extension แต่ก็ไม่ได้รับรองว่าไฟล์มันเป็นจริงตามนามสกุลที่ส่งมา จุดที่อันตรายก็เลยต้องมาตรวจชนิดไฟล์ในผั่ง server อยู่เหมือนเดิม

ค่าที่ใส่ใน accept คือ MIME Types ดูเพิ่มเติมได้ที่ The Complete List of MIME Types