Tag Archive CodeIgniter

ERR_CONTENT_DECODING_FAILED

ไปเปิด option บีบอัดข้อมูลใน CodeIgniter

$config['compress_output'] = true;

หลังเปิดเว็บก็ดูปกติดี จนเกือบจะเลิกเทสไปละ จนมาเจอว่า javaScript ที่เคยใช้ได้ปกติกับมี error เปิดไฟล์ออกมาดูใน chrome มันขึ้น error

หน้าเว็บใน http://xxx อาจหยุดให้บริการชั่วคราวหรืออาจถูกย้ายไปยังที่อยู่เว็บใหม่อย่างถาวร
ERR_CONTENT_DECODING_FAILED

เจอว่าเกิดได้จากหลายสาเหตุมากแต่เพราะเพิ่งไปเปิด zlib มาเลยเน้นมันเป็นพิเศษ จนเจอว่าไปแก้ php.ini เปลี่ยน

zlib.output_compression = On

ก็แก้ได้แล้ว

เวลาเขียน program อะไรเล็กๆ น้อยๆ ก็ทำให้ระบบเปลี่ยนแปลงได้เสมอ

Fixing ERR_CONTENT_DECODING_FAILED in Apache+PHP

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

CodeIgniter: Composer

โดยปกติ composer จะเก็บไฟล์โดยสร้าง folder vendor ใน folder เดียวกับไฟล์ composer.json

ใน codeinigter ว่างไฟล์ composer.json ไว้นอกสุดแต่ในไฟล์ \application\config\config.php กลับเขียน

/*
  |--------------------------------------------------------------------------
  | Composer auto-loading
  |--------------------------------------------------------------------------
  |
  | Enabling this setting will tell CodeIgniter to look for a Composer
  | package auto-loader script in application/vendor/autoload.php.
  |
  |    $config['composer_autoload'] = TRUE;
  |
  | Or if you have your vendor/ directory located somewhere else, you
  | can opt to set a specific path as well:
  |
  |    $config['composer_autoload'] = '/path/to/vendor/autoload.php';
  |
  | For more information about Composer, please visit http://getcomposer.org/
  |
  | Note: This will NOT disable or override the CodeIgniter-specific
  |    autoloading (application/config/autoload.php)
  */

คือ พี่แกให้เก็บไฟล์ไว้ที่ application/vendor ไม่ใช่ /vendor

ปัญหานี้แก้ได้โดยเพิ่ม

{
  ...
  "config": {
  "vendor-dir": "application/vendor"
  },
  ...
}

หลังจากนั้นก็ไปเปิด auto-load โดยเปลี่ยน

$config['composer_autoload'] = false;

เป็น

$config['composer_autoload'] = true;

แล้วทดลองใช้ command

composer update

จะเห็นว่าไฟล์เข้าไปที่ application/vendor แล้ว

ถ้า composer โหลดไฟล์มาไม่ได้เพราะติด proxy อ่าน

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

CodeIgniter: แยก config

การดึงค่าคอนฟิกของโค้ทอินิกเตอร์สามารถทำได้โดย ใช้คำสั่ง

$this->config->item(' ตัวแปร ');

โดยจะดึงมาจากไฟล์ \application\config\config.php เป็นหลัก แต่ถ้าต้องการแยก config ออกมาเป็นส่วนๆ เพื่อความง่ายในการจัดการ สามารถสร้างไฟล์ ขึ้นมาใน application\config ได้

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

$config['caching']['adapter'] = 'memcached';
$config['caching']['backup']  = 'file';

จากนั้นเราจะอ่าน configuration เข้ามาในระบบของเราสามารถทำได้ 2 วิธีคือ

  1. เป็นค่าที่เราต้องใช้บ่อยๆแทบทุกหน้า เพิ่มเข้าไปใน Auto-loading เปิดไฟล์ \application\config\autoload.php เพิ่มชื่อไฟล์ลงไปใน
    $autoload['config']

    เช่น

    ...
    $autoload['config'] = ['caching'];
    ...
  2. ถ้าต้องการใช้เฉพาะบางไฟล์ ทำได้โดยการ load ใน controller ที่ต้องการโดยใช้คำสั่ง
    ...
    $this->config->load('caching');
    ...

ผมใช้หน้าแรกแสดงตัวอย่างการใช้

<?php
defined('BASEPATH') or exit('No direct script access allowed');

class Welcome extends CI_Controller
{
    public function __construct()
    {
        parent::__construct();

        echo 'charset = ' . $this->config->item('charset');

        //$this->config->load('caching');

        echo '<pre>', print_r($this->config->item('caching'), true), '</pre>';
    }
...

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

Custom Rules Validation

ตัวอย่างการเขียน custom rule validation

<?php
class FormValidationCustomRules extends CI_Controller
{

    public function __construct()
    {
        parent::__construct();
        // Your own constructor code
    }

    public function uploadJPEG()
    {
        $this->form_validation->set_rules('cover', 'JPEG Upload', 'trim|xss_clean');

        if ($this->form_validation->run() == true) {
            $fileDir = 'assets/contents/';
            $fileName = date('U') . '.jpeg';

            $config = [
                'allowed_types' => 'jfi|jfif|jif|jpe|jpeg|jpg',
                'file_ext_tolower' => true,
                'file_name' => $fileName,
                'max_size' => '10000',
                'overwrite' => false,
                'upload_path' => $fileDir,
            ];

            $this->load->library('upload', $config);

            if ($this->upload->do_upload('cover', false)) {
                $this->uploadFile = $fileDir . $fileName;
                return true;
            } else {
                $this->form_validation->set_message('uploadJPEG', $data['error'] = $this->upload->display_errors());

                if ($_FILES['cover']['error'] != 4) {
                    return false;
                }
            }
        }

        return false;
    }

    public function index()
    {
        $this->load->library('form_validation');

        $formValidation = [
            [
                'field' => 'cover',
                'label' => 'JPEG Upload',
                'rules' => 'callback_uploadJPEG',
            ],
        ];
        $this->form_validation->set_rules($formValidation);

        if ($this->form_validation->run() == true) {
            echo 'upload file to ', $this->uploadFile, '<br><img alt="', $this->uploadFile, '" class="img-thumbnail" src="../', $this->uploadFile, '">';
        }

        $this->load->view('FormValidation/CustomRules');
    }
}

หลักการคือ

  • สร้าง function ขึ้นมา แล้วเรียกใช้โดยมี callback_ นำหน้า
  • ส่ง message กลับมาโดยใช้ $this->form_validation->set_message(‘function name’,’ข้อความ’)

config codeigniter by environments

ที่ทำงานมี process ในการพัฒนา development > test > production โดยแต่ละ server จะมี config และ database แยกออกจากกันเพื่อความปลอดภัย โดย codeigniter สามารถแยก config ได้โดยการเปลี่ยน Environments ซึ่งโดยปกติจะมี 3 สภาพแวดล้อมคือ development, production, testing และแล้วแต่ท่านจะตั้ง

การทำระบบ config สามารถทำได้โดย

  1. ได้โดยเปิดไฟล์ \.htaccess เพิ่ม
    ...
    SetEnv CI_ENV development
    ...

    เข้าไป หรือเข้าไปแก้ไฟล์ \index.php แก้บรรทัด

    define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');

    เป็น

    define('ENVIRONMENT', 'development');
  2. ไปที่ \application\config สร้าง folder ไว้เก็บ configuration ตามชื่อ Environments เช่น \application\config\development, \application\config\production, \application\config\testing
  3. copy config ไฟล์ มาจาก \application\config จากนั้นก็ลบข้อมูลเดิมออกแล้วใส่เฉพาะส่วนที่แตกต่างกันเช่น \application\config\development\constants.php
    <?php
    defined('BASEPATH') or exit('No direct script access allowed');
    
    define('TITLE', 'development');
    

    ทำแบบเดียวกันกับไฟล์อื่นๆ ถ้ามี config ที่ต่างกัน เช่น \application\config\development\database.php

  4. ทดสอบโดยเปิดไฟล์ \application\views\welcome_message.php แก้เป็น
    <?php
    defined('BASEPATH') or exit('No direct script access allowed');
    ?><!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="utf-8">
    	<title><?=TITLE;?></title>
    
    	<style type="text/css">
    
    	::selection { background-color: #E13300; color: white; }
    	::-moz-selection { background-color: #E13300; color: white; }
    
    	body {
    		background-color: #fff;
    		margin: 40px;
    		font: 13px/20px normal Helvetica, Arial, sans-serif;
    		color: #4F5155;
    	}
    
    	a {
    		color: #003399;
    		background-color: transparent;
    		font-weight: normal;
    	}
    
    	h1 {
    		color: #444;
    		background-color: transparent;
    		border-bottom: 1px solid #D0D0D0;
    		font-size: 19px;
    		font-weight: normal;
    		margin: 0 0 14px 0;
    		padding: 14px 15px 10px 15px;
    	}
    
    	code {
    		font-family: Consolas, Monaco, Courier New, Courier, monospace;
    		font-size: 12px;
    		background-color: #f9f9f9;
    		border: 1px solid #D0D0D0;
    		color: #002166;
    		display: block;
    		margin: 14px 0 14px 0;
    		padding: 12px 10px 12px 10px;
    	}
    
    	#body {
    		margin: 0 15px 0 15px;
    	}
    
    	p.footer {
    		text-align: right;
    		font-size: 11px;
    		border-top: 1px solid #D0D0D0;
    		line-height: 32px;
    		padding: 0 10px 0 10px;
    		margin: 20px 0 0 0;
    	}
    
    	#container {
    		margin: 10px;
    		border: 1px solid #D0D0D0;
    		box-shadow: 0 0 8px #D0D0D0;
    	}
    	</style>
    </head>
    <body>
    
    <div id="container">
    	<h1>Welcome to CodeIgniter!</h1>
    
    	<div id="body">
    <?php
    echo '<br>ENVIRONMENT = ' . ENVIRONMENT;
    echo '<br>FILE_READ_MODE = ' . FILE_READ_MODE;
    echo '<br>title = ' . TITLE;
    ?>
    	</div>
    
    	<p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo (ENVIRONMENT === 'development') ? 'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : ''; ?></p>
    </div>
    
    </body>
    </html>
  5. เปิดหน้าแรกและสังเกตผลลัพธ์

ค่าในไฟล์ config จะถูกเพิ่มจากของเดิมโดยเลือกมาจากไฟล์ใน folder ที่ชื่อเดียวกับ environments ไม่ใช่แทนที่ของเดิมสังเกตได้จากค่า FILE_READ_MODE ที่ไม่มีในไฟล์ \application\config\development\constants.php ที่เราแยกออกมา

Codeigniter reused active record query

ในการเขียน query บางครั้งก็ต้องเขียนคิวรี่ที่ต่างกันเล็กๆ น้อยๆ เช่น ต้องแบ่ง list ข้อมูลออกเป็นหน้าๆ หรือที่เรียกกันว่า pagination จะมี 2 query ที่ต้องใช้คือ query ที่นับ ข้อมูลที่มีทั้งหมด

SELECT `d`.`district_id`,
       `d`.`enable`,
       `d`.`district_code`,
       `d`.`district_name`,
       `p`.`province_name`
FROM   `district` AS `d`
       LEFT JOIN `province` AS `p`
              ON `d`.`province_id` = `p`.`province_id`

และ query ที่ดึงข้อมูลเฉพาะช่วงที่กำหนด

SELECT `d`.`district_id`,
       `d`.`enable`,
       `d`.`district_code`,
       `d`.`district_name`,
       `p`.`province_name`
FROM   `district` AS `d`
       LEFT JOIN `province` AS `p`
              ON `d`.`province_id` = `p`.`province_id`
LIMIT  0, 10

จะเห็นว่า ต่างกันแค่ LIMIT 0, 10 เท่านั้น แต่เพราะว่า ไม่ควร query ข้อมูล ที่ไม่ได้ใช้ จึงเปลี่ยน

SELECT COUNT(district_id) AS recordsTotal
FROM   `district` AS `d`
       LEFT JOIN `province` AS `p`
              ON `d`.`province_id` = `p`.`province_id`

แก้ select ให้เป็น SELECT COUNT(DISTRICT_ID) AS recordsTotal แทนที่จะเลือกหลายๆ column หลาย row มาเพื่อแค่จะนับว่ามีข้อมูลกี่ record แค่นั้นเอง

ยังยุ่งไม่พอ เมื่อทำเป็น data table หรือ grid จะมีเงื่อนไขอย่างเช่น filter ข้อมูล หรือ order ข้อมูลใหม่ตาม column ต่างๆ ที่ user ปลับเปลี่ยนเวลาใช้งาน ถ้าต้องเขียนเงื่อนใขเพิ่ม ถ้าเป็น query string อย่าง DISTRICT_ID = ‘xxx’ ก็พอจะเก็บในตัวแปรแล้วเอามาต่อกันได้ แต่ถ้าเขียนเป็น active record ก็ลำบากมากที่ต้องมาเขียนใหม่หลายๆจุด แต่ Codeigniter มีวิธี reused active record มาใช้ใหม่ได้ลดความซับซ้อนลงไปได้เยอะเลย

วิธีการคือเขียน query ส่วนที่ใช้ ร่วมกัน ระหว่าง ->start_cache(); และ ->stop_cache(); จากนั้นเขียน ส่วนอื่นเพิ่มเข้าไป เป็นวิธีที่ฉลาดมากๆ

<?php

class DatabasecachingModel extends CI_Model
{

    public function __construct()
    {
        // Call the CI_Model constructor
        parent::__construct();

        $this->db = $this->load->database('db', true);
    }

    public function getPagination()
    {
        $post = $this->input->post();

        // Turn caching on
        $this->db->start_cache();

        $this->db->from('district AS d');
        $this->db->join('province AS p', 'd.PROVINCE_ID = p.PROVINCE_ID', 'left');

        if (isset($post['DISTRICT_ID'])) {
            $this->db->where('DISTRICT_ID', $post['DISTRICT_ID']);
        }

        if (isset($post['PROVINCE_ID'])) {
            $this->db->where('PROVINCE_ID', $post['PROVINCE_ID']);
        }

        $this->db->stop_cache();

        $this->db->select('COUNT(DISTRICT_ID) AS recordsTotal');
        $recordsTotal = $this->db->get()->row()->recordsTotal;

        echo '<br><br> query string for count = ' . $this->db->last_query();
        echo '<br> records total = ' . $recordsTotal;

        $this->db->select('d.DISTRICT_ID, d.enable, d.DISTRICT_CODE, d.DISTRICT_NAME, p.province_NAME');
        $this->db->limit(10, 0);
        $results = $this->db->get()->result_array();

        echo '<br><br> query string for results = ' . $this->db->last_query();
        echo '<pre>', print_r($results, true), '<pre>';

    }

}

เก็บ CodeIgniter log ด้วย hook

วิธีที่จะพัฒนาและดูแลเว็บคือทำระบบ log ที่จะบันทึกข้อมูลการใช้งาน ซึ่งจะบันทึกสิ่งที่เกิดขึ้นไว้สำหรับเข้ามาดูเหตุการณ์ที่เกิดขึ้นย้อนหลังได้ มีประโยชน์ในการดูแลระบบโดยเฉพาะตัวที่เป็น API ให้ระบบอื่นๆเรียกใช้ สำหรับ ci เราสามารถเขียนได้โดยการใช้ hook

ระบบ Hook (ตะขอ) คือ เป็นตะขอที่เกี่ยวกับเหตุการณ์ซักอย่างแล้วจึงทำงาน เหมือนกับ tricker ในดาต้าเบส หรือจะ อธิบายการทำงานง่ายๆ ก็เหมือน คุณไปที่ร้านอาหารคิดไม่ออกว่าจะทานอะไร ใช้วิธีรอให้เพื่อนสั่งแล้วบอกว่า หมีทู่ (me too.) นั้นละครับ

  1. ก่อนอื่น ไปเปิดการใช้งาน hook ก่อน เปิดไฟล์ /application /config/config.php แก้ $config[‘enable_hooks’] = FALSE; เป็น TRUE;
  2. เปิดไฟล์ /application /config/ hooks.php เพิ่มบรรทัด
    $hook['post_system'][] = array(
            'class' => '',
            'function' => 'log_Profiling',
            'filename' => 'log_Profiling.php',
            'filepath' => 'hooks'
    );
    
  3. จากนั้นไปสร้างไฟล์ log_Profiling.php ใน /application/hooks เนื้อหาตามนี้ครับ
    <?php
    function log_Profiling(){
    global $CI ,$application_folder;
    	$output = '<html><body>';
    	$output .= '<fieldset id="ci_profiler_benchmarks" style="border:1px solid #c00000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee">
    <legend style="color:#c00000;">OUTPUT</legend>'.$CI->output->get_output().'</fieldset>';
    	if( ! isset($_POST['profiler'])){
    		$CI->load->library('profiler');
    		if ( ! empty($CI->_profiler_sections)){
    			$CI->profiler->set_sections($this->_profiler_sections);
    		}
    		$output .= $CI->profiler->run();
    	}
    	$output .= '</body></html>';
    	$fp = fopen($application_folder.'/logs/Profiling/'.date('Y-m-d-H-i-s-U').'_'.$CI->router->fetch_class().'_'.$CI->router->fetch_method().'.html' ,'w');
    	flock($fp ,LOCK_EX);
    	fwrite($fp ,$output);
    	flock($fp ,LOCK_UN);
    	fclose($fp);
    }
    
  4. สร้างโฟลเดอร์ application/logs/Profiling/

แก้ระบบ error ของ CodeIgniter สำหรับ API

เดิมการแสดง error จะแสดงออกมาเป็น html แต่เมื่อเรานำ CI มาใช้เป็นระบบ API ถ้าแสดงแบบเดิมจะเกิดปัญหา app บน iphone / ipad ล่ม เพราะว่าข้อมูลที่ส่งออกไป กับที่ ios ทั้งหลายคาดว่าจะได้รับไม่ตรงกัน แก้ไม่ยากครับ แค่แทนที่ไฟล์ใน application/errors จาก code ด้านล่าง

error_404.php

<?php
global $application_folder;

// Get an article from the database, show a 404 page if the requested article was not found.

	$article = get_content($this->uri->uri_string());

	if(empty($article)){
		show_404($this->uri->uri_string());
	}

$datas['status'] = -1;
$datas['type'] = '404';
$datas['messageHeading'] = '404';
$datas['message'] = 'file not found';

$logs = "nnn".date('Y-m-d H:i:s');
$logs = $logs."ntURLt".$_SERVER['SERVER_ADDR'].$_SERVER['REQUEST_URI'];
$logs = $logs."ntPOSTt".print_r($_POST ,true);
$logs = $logs."ntRETURNt".print_r($datas ,true);
$fp = fopen($application_folder.'/logs/error'.date('Y-m-d').'.txt' ,'a+');
flock($fp ,LOCK_EX);
fwrite($fp ,$logs);
flock($fp ,LOCK_UN);
fclose($fp);
exit(json_encode($datas));

error_db.php

<?php
global $application_folder;
$datas['status'] = -1;
$datas['code'] = 1;
$datas['type'] = 'database';
$datas['messageHeading'] = $heading;
$datas['message'] = 'database error';
$datas['message'] = $message;

$logs = "nnn".date('Y-m-d H:i:s');
$logs = $logs."ntURLt".$_SERVER['SERVER_ADDR'].$_SERVER['REQUEST_URI'];
$logs = $logs."ntPOSTt".print_r($_POST ,true);
$logs = $logs."ntRETURNt".print_r($datas ,true);
$fp = fopen($application_folder.'/logs/error'.date('Y-m-d').'.txt' ,'a+');
flock($fp ,LOCK_EX);
fwrite($fp ,$logs);
flock($fp ,LOCK_UN);
fclose($fp);
exit(json_encode($datas));

error_general.php

<?php
global $application_folder;
$datas['status'] = -1;
$datas['type'] = 'general';
$datas['messageHeading'] = $heading;
$datas['message'] = $message;

$logs = "nnn".date('Y-m-d H:i:s');
$logs = $logs."ntURLt".$_SERVER['SERVER_ADDR'].$_SERVER['REQUEST_URI'];
$logs = $logs."ntPOSTt".print_r($_POST ,true);
$logs = $logs."ntRETURNt".print_r($datas ,true);
$fp = fopen($application_folder.'/logs/error'.date('Y-m-d').'.txt' ,'a+');
flock($fp ,LOCK_EX);
fwrite($fp ,$logs);
flock($fp ,LOCK_UN);
fclose($fp);
exit(json_encode($datas));

error_php.php

<?php
global $application_folder;
$datas['status'] = -1;
$datas['type'] = 'php';
$datas['messageHeading'] = 'A PHP Error was encountered';
$datas['message'] = $message;
$datas['severity'] = $severity;
$datas['filepath'] = $filepath;
$datas['line'] = $line;

$logs = "nnn".date('Y-m-d H:i:s');
$logs = $logs."ntURLt".$_SERVER['SERVER_ADDR'].$_SERVER['REQUEST_URI'];
$logs = $logs."ntPOSTt".print_r($_POST ,true);
$logs = $logs."ntRETURNt".print_r($datas ,true);
$fp = fopen($application_folder.'/logs/error'.date('Y-m-d').'.txt' ,'a+');
flock($fp ,LOCK_EX);
fwrite($fp ,$logs);
flock($fp ,LOCK_UN);
fclose($fp);
exit(json_encode($datas));

เท่านี้ error ทั้งหลายจะแปลงกายไปเป็น แบบ json และบันทึกลงไฟล์ใน application/logs เป็นรายวัน