2016/12/20

Webpack With Vendor

ๅ‰่จ€

ไน‹ๅ‰ๅฏซ้Ž้€™็ฏ‡ webpack,ๅ–ฎไธ€่จญๅฎš webpack ็š„ๆ–นๅผ,ไธ€่ˆฌไพ†่ชช็‚บไบ†ๆธ›ๅฐ‘ request,ๆ‰€ไปฅๆœƒๅธŒๆœ›ๅฐ‡ js ๆช”ๆกˆ compile ๆˆไธ€ๅ€‹,้€™็จฎๆขไปถไฝ ไธๆ˜ฏๅพž้ ญๅˆฐๅฐพๆ‰“้€ ้€™ๅ€‹็ถฒ็ซ™็š„ไฝœ่€…,ไบ†่งฃๆฏๅ€‹้ ้ข dom ๅธƒๅฑ€็š„่ฉฑๆ˜ฏ็›ธ็•ถๅ›ฐ้›ฃ็š„,่€Œไธ”ๅพž HTTP/2 ็š„ๆ–ฐๆจ™ๆบ–ๅ‡บ็พไปฅๅพŒ,้€™ๆ‹›ๅทฒ็ถ“ๆฒ’ๆœ‰ๆ˜Ž้กฏ็š„ๅ„ชๅ‹ขไบ†,ๅฏไปฅๅƒ่€ƒ 「ไฝ ็š„็ถฒ็ซ™ๅ‡็ดšๅˆฐ HTTP/2 ไบ†ๅ—Ž?」้€™็ฏ‡ๆ–‡็ซ 。

ๆ‰€ไปฅ้€™็ฏ‡ๆ–‡็ซ ๆœƒ้‡ๆ–ฐๆ•™ๅญธๆ€Ž้บผ่จญๅฎš,่ฎ“ไฝ ๆฏๅ€‹็ถฒ้ ๆœ‰ๅฑฌๆ–ผ่‡ชๅทฑ็š„ js ๆช”ๆกˆ,ไฝ†ๅ…ฑ็”จ็š„ๅฅ—ไปถๅฆ‚ jQuery ๆˆ– bootstrap ๅปๅฏไปฅ็จ็ซ‹,ๆธ›ๅฐ‘็จ็ซ‹ๆช”ๆกˆ็š„ๅคงๅฐ。

ๅฎ‰่ฃ็›ธ้—œๅฅ—ไปถ

npm i --save-dev webpack babel-core babel-loader babel-preset-es2015
npm i --save jquery bootstrap

็›ฎๅ‰ไธป่ฆ้‚„ๆ˜ฏ็”จ babel ็ทจ่ญฏ่ผƒๆ–ฐ็ฉŽ็š„ JavaScript ่ชžๆณ•。

ๆช”ๆกˆๅธƒๅฑ€

webpack.config.js
const webpack = require('webpack');
const path = require('path');

module.exports = {
    entry: {
        a: path.resolve(__dirname, 'js/src/a'),
        b: path.resolve(__dirname, 'js/src/b'),
        vendor: ['jquery', 'bootstrap']
    },
    output: {
        path: path.resolve(__dirname, 'js/build/'),
        filename: '[name].js'
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js'),
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery'
        }),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            }
        })
    ],
    module: {
        loaders: [
            { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }
        ]
    }
};

้€™ๅ€‹่จญๅฎšๆช”้ ่จˆ่ฆๅฐ‡ js/src/ ไธ‹็š„ a.js ไปฅๅŠ b.js compile ๅˆฐ js/build/,ไธฆๅฐ‡ jQuery ไปฅๅŠ bootstrap ๆŠฝๅ‡บไพ†ๆˆ็‚บ vendor,่จญๅฎšๅฎŒๆˆๅพŒ,ๅœจๆ น็›ฎ้Œ„ๅŸท่กŒ webpack,็ทจ่ญฏๅพŒๅœจ js/build/ ไธ‹ๆœƒ็œ‹ๅˆฐ a.js, b.js, vendor.bundle.js ไธ‰ๅ€‹ๆช”ๆกˆ。

.babelrc
{
  "presets": ["es2015"]
}

้€™ๆ˜ฏ babel ็š„่จญๅฎšๆช”。

js/src/a.js
$(function() {
    $('body').append('this is a');
});
js/src/b.js
$(function() {
    $('body').append('this is a');
});
js/src/b.js
$(function() {
    $('body').append('this is b');
});
a.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webpack page a</title>
    <script src="js/build/vendor.bundle.js"></script>
    <script src="js/build/a.js"></script>
</head>
<body>
    <h3>this is a</h3>
</body>
</html>
b.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webpack page b</title>
    <script src="js/build/vendor.bundle.js"></script>
    <script src="js/build/b.js"></script>
</head>
<body>
    <h3>this is b</h3>
</body>
</html>

ๅŸท่กŒ a.htmlไปฅๅŠ b.html ๅฐฑๆœƒ็œ‹ๅˆฐๅ„่‡ช็š„ๆ•ˆๆžœไบ†。

2016/12/18

Google reCAPTCHA On Codeigniter

ๅ‰่จ€

็‚บไบ†้ฟๅ…็ถฒ็ซ™่ขซ robot ๆŽƒๆจกๅš้‡่ค‡ๆ€ง็š„ๅ‹•ไฝœ,ไพ‹ๅฆ‚ๅŠ ๅ…ฅๆœƒๅ“ก,็”ณ่ซ‹ๅฟ˜่จ˜ๅฏ†็ขผ็ญ‰็ญ‰,ๆˆ‘ๅ€‘ๆœƒๆ”พไธ€ๅ€‹ๅฟ…้ ˆไบบ็‚บ่ผธๅ…ฅ็š„ๆฌ„ไฝไธฆไธ”่ฎ“ robot ้›ฃไปฅ่พจ่ญ˜็ ด่งฃ,ๅธธ่ฆ‹็š„ๆœƒๆœ‰ๆ–‡ๅญ—ไปฅๅŠๆ•ธๅญ—็š„ๅœ–ๅƒๅŒ–่ผธๅ…ฅ,ไฝ†ๆœ‰็š„ๆฉŸๅ™จไบบๅฆ‚ๆžœๆ‹ฟๅˆฐ่ฆๅพ‹ไปฅๅŠ่ถณๅค ็š„ๆจฃๆœฌ,็ด”ๆ–‡ๅญ—็š„่ผธๅ…ฅๆ–นๅผๆ˜ฏๅฏ่ƒฝ่ขซ็ ด่งฃ็š„,Google ๅ‡บ็š„ reCaptcha ๅฑฌๆ–ผๅœ–ๅƒๅŒ–็š„้ธๆ“‡้ฉ—่ญ‰,ไธ็ฎกๆ˜ฏๆŽ’ๅˆ—ไฝ็ฝฎๆˆ–ๆ˜ฏ็จฎ้กž็š„ๅคšๆจฃๆ€ง้ƒฝ้›ฃไปฅๅŽป็ ด่งฃ,ๅœจ้€™้‚Š็คบ็ฏ„ไธ€ไธ‹ๆ€Ž้บผๆ•ดๅˆ ci ไฝฟ็”จ

ๅฏฆๅš

ๅฅ—ไปถๅฎ‰่ฃ

้ฆ–ๅ…ˆๅฎ‰่ฃ google/recaptcha ้€™ๅ€‹ๅฅ—ไปถ,ๆˆ‘ๅœจ codeigniter ไธŠๆœ‰ไฝฟ็”จ composer,ๅœจ config/config.php ไธ‹ๅฏไปฅๆ‰“้–‹,ไฝฟ็”จๆ–นๆณ•่ทŸๅœจ Laravel ไธŠไธ€ๆจฃ

็จ‹ๅผ็ขผ

application/controllers/Recaptcha.php
<?php

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

class Recaptcha extends CI_Controller
{
    public function index()
    {
        $this->load->helper('form');
        $this->load->helper('url');
        $this->load->view('recaptcha/form');
    }

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

        $status = 'done';
        $message = 'done';
        $secret = '6LfsIQ8UAAAAAOveAzcFb6A_3Yiv_QdfR-qo5qld';

        try {
            $this->form_validation->set_rules('username', 'username', 'required');
            $this->form_validation->set_rules('g-recaptcha-response', 'captcha', 'required');

            if (!$this->form_validation->run()) {
                throw new Exception(validation_errors(null, null));
            }

            $gRecaptchaResponse = $this->input->post('g-recaptcha-response');
            $remoteIp = $this->input->ip_address();
            $recaptcha = new \ReCaptcha\ReCaptcha($secret);
            $resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp);

            if (!$resp->isSuccess()) {
                $errors = $resp->getErrorCodes();
                throw new Exception(current($errors));
            }
        } catch (Exception $e) {
            $status = 'fail';
            $message = $e->getMessage();
        }

        $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode(compact('status', 'message')));
    }
}
application/views/recaptcha/form.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>reCAPTCHA Demo</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script src='https://www.google.com/recaptcha/api.js'></script>
    <script type="text/javascript" charset="utf-8">
    var baseUrl = "<?php echo base_url(); ?>";

    $(function() {
        $('#recaptcha_form').on('submit', function() {
            var data = $(this).serialize();

            $.post(baseUrl + 'recaptcha/result', data, function(response) {
                alert(response.message);

                if (response.status === 'done') {
                    grecaptcha.reset();
                }
            }, 'json');

            return false;
        });
    });
    </script>
</head>
<body>
    <?php echo form_open('recaptcha/result', ['id' => 'recaptcha_form']); ?>
    <div><?php echo form_input('uername', 'chan'); ?></div>
    <div class="g-recaptcha" data-sitekey="6LfsIQ8UAAAAAFmYCwSLpfKgWtqK1SlVfMcPn2Q6"></div>
    <div><?php echo form_submit('go', 'go'); ?></div>
    <?php echo form_close(); ?>
</body>
</html>

ไฝฟ็”จ reCAPTCHA ่ฆๅ…ˆๅŽป็”ณ่ซ‹ key ่ทŸ secret,้€™้ƒจไปฝๆˆ‘ๅฐฑไธ่ฌ›่งฃไบ†,้€™ไปฝ็จ‹ๅผ็ขผไธป่ฆๅŠŸ่ƒฝๅฐฑๆ˜ฏ้ฉ—่ญ‰ๆ˜ฏๅฆๆœ‰่ผธๅ…ฅ username ไปฅๅŠ reCAPTCHA,ๆœ‰็š„่ฉฑๅ†้€ฒไธ€ๆญฅ้ฉ—่ญ‰ captcha ๆญฃ็ขบๆ€ง,ๅฆ‚ๆžœไฝ ไธๆƒณไฝฟ็”จๅฅ—ไปถ็š„้Œฏ่ชค่จŠๆฏ,้‚ฃไธ€ๆ—ฆๅ ฑ้Œฏไฝ ๅช่ฆ้กฏ็คบ captcha ้Œฏ่ชคๅณๅฏ,ๆœ‰ไบ›่กจๅ–ฎ้€ๅ‡บๅพŒไธไธ€ๅฎšๆœƒๆ›้ ,ๆ‰€ไปฅๆˆ‘ๅŠ ไบ†ๅ€‹ script ๅฆ‚ๆžœๅตๆธฌๅˆฐ้€™ๆฌก็š„่กŒ็‚บๆญฃ็ขบ็š„ๆ™‚ๅ€™ refresh ไธ€ๅ€‹ๆ–ฐ็š„ captcha,่ชžๆณ•็š„ไฝฟ็”จๆ™‚ๆฉŸๅฏไปฅ็œ‹ไฝฟ็”จ่€…็š„ไฝฟ็”จๆƒ…ๆณๅŽป่ชฟๆ•ดๆญ้…

2016/11/30

Docker On Windows

enter image description here

ๅ‰่จ€

ๆˆ‘็š„ๅทฅไฝœ็’ฐๅขƒๆ˜ฏ Windows,ไฝ†ๅพˆ็ฟ’ๆ…ฃไฝฟ็”จ command line ๅทฅไฝœ,้›–็„ถ Windows ๆœ‰ไธ€ไบ›ๅทฅๅ…ทๅฏไปฅๆจกๆ“ฌ,ๅƒๆ˜ฏ Cygwin,ๆˆ–่€…ๆ˜ฏ cmder,ไฝ†้ƒฝๅช่ƒฝ่ชชๅ ช็”จ่€Œๅทฒ,ๆ‰€ไปฅๆˆ‘็ฟ’ๆ…ฃๅœจ Windows ไธŠๅฎ‰่ฃ Vagrant ็•ถไฝœๅทฅไฝœ็’ฐๅขƒ,ไน…ไปฐ docker ๅคงๅ,ๆœ€่ฟ‘่Šฑไบ†้ปžๆ™‚้–“็ ”็ฉถ,ไปŠๅคฉ้€™็ฏ‡ๆ–‡็ซ ๆœƒไธ€ๅ€‹ไธ€ๅ€‹ๆญฅ้ฉŸๅธถๅˆฐๆ€Ž้บผๅœจ Windows ไฝฟ็”จ docker toolbox ๅฎ‰่ฃไธ€ๅ€‹ PHP7 container by ubuntu xenail ้€ฃ็ตๅฆไธ€ๅ€‹ mysql container

้–‹ๅง‹ Docker ไน‹ๆ—…

้ฆ–ๅ…ˆๅŽป docker tool ไธ‹่ผ‰้ ้ข,ไธ‹่ผ‰ Windows ๅฎ‰่ฃๆช”,ไน‹ๅพŒไพฟๆ˜ฏ็„ก็ชฎ็š„ไธ‹ไธ€ๆญฅ,้€™้‚Šไป‹็ดนไธ€ไธ‹้€™ๅ€‹ๅทฅๅ…ท็š„้‹ไฝœๆ–นๅผ,ไป–ๆœƒไฝฟ็”จ docker-machine ็š„ vm ๆŠ€่ก“้€้Ž virtualbox build ไธ€ๅ€‹่™›ๆ“ฌ็’ฐๅขƒ่ฎ“ไฝ ่ท‘ docker command,ๆ‰€ไปฅๅฎ‰่ฃๆˆๅŠŸๅพŒๆœƒๆœ‰ Docker Quickstart Terminal ๅฏไปฅ็”จ,ไฝ†ไป–ๅฐฑ่ทŸๅ…ถไป–ๆจกๆ“ฌ bash ็’ฐๅขƒ็š„่ปŸ้ซ”ไธ€ๆจฃๅชๆ˜ฏๅ ช็”จ่€Œๅทฒ,ๆ‰€ไปฅๆˆ‘ๆ‰“็ฎ—ไฝฟ็”จ xshell ๅŽป่ตฐ้€™ๅ€‹ demo,ไนŸๅฏไปฅไฝฟ็”จ putty

ๅฎ‰่ฃๅฎŒๆˆๅพŒ docker vm ้ ่จญ็š„ ip ๆ˜ฏ 192.168.99.100,ssh 192.168.99.100 ไปฅๅพŒๆœƒๅ•ไฝ ๅธณๅฏ†,ๅˆ†ๅˆฅๆ˜ฏ docker ไปฅๅŠ tcuser,้€ฒๅ…ฅไปฅๅพŒๆˆ‘ๅ€‘ๅฐฑๅฏไปฅไฝฟ็”จๆ‰€ๆœ‰็š„ docker command,ๆˆ‘ไปŠๅคฉ่ฆไฝฟ็”จ ubuntu ่ทŸ mysql/mysql-server ้€™ๅ…ฉๅ€‹ container,็•ถ็„ถไธ€ๅฎšไนŸๆœ‰ build ๅฅฝ็š„ lamp image,ไฝ†ๆˆ‘ๆ‰“็ฎ— step by step ็ด€้Œ„ไธ€ไธ‹,่‡ณๆ–ผ docker ็š„ไธ€ไบ›ๅŸบ็คŽๅ‘ฝไปคๆˆ‘ไธๆœƒๅคšๅš่งฃ้‡‹,ๅฏไปฅๅŽป Docker —— ๅพžๅ…ฅ้–€ๅˆฐๅฏฆ่ธ ็œ‹ไธ€ไธ‹,ๆˆ‘ๅ€‘ๅ…ˆ pull ไธ€ไธ‹

$ docker pull ubuntu
$ docker pull mysql/mysql-server

$ docker images

REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
ubuntu               latest              4ca3a192ff2a        12 hours ago        128.2 MB
mysql/mysql-server   latest              6272a6121ff6        7 days ago          316.2 MB

ๅทฒ็ถ“้ †ๅˆฉๅฐ‡้€™ๅ…ฉๅ€‹ container ๆŠ“ไธ‹ไพ†,ๅ…ˆไพ†่จญๅฎš database

$ docker run --name db1 -e MYSQL_ROOT_PASSWORD=123456 -d mysql/mysql-server
$ docker ps

CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                 NAMES
dfc880ed429d        mysql/mysql-server   "/entrypoint.sh mysql"   18 seconds ago      Up 17 seconds       3306/tcp, 33060/tcp   db1

ไธŠ่ฟฐๆŒ‡ไปคๅปบ็ซ‹ไบ†ไธ€ๅ€‹ๅๅซ db1 ็š„ mysql server,root ๅฏ†็ขผ็‚บ 123456,ไฝ†้ ่จญๅธณ่™Ÿๅชๆœ‰ root@local,ๆ‰€ไปฅๆˆ‘ๅ€‘ๅฟ…้ ˆๅปบไธ€ๅ€‹ root@% ็š„ๅธณ่™Ÿไพ†ไฝฟ็”จ,้ †ไพฟๅปบ็ซ‹ไธ€ๅ€‹่ณ‡ๆ–™่กจไพ†ๆธฌ่ฉฆ

$ docker exec -it db1 mysql -uroot -p123456
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
create database test;

mysql> use test;

mysql> CREATE TABLE `tests` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(50) NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

mysql> INSERT INTO `tests` (`name`) VALUES ('a'), ('b');

mysql> exit;

ๅˆฐๆญค mysql-server ็š„้ƒจไปฝๅฐฑๅฎŒๆˆไบ†,็พๅœจไพ†้€ฒ่กŒ web ็š„้ƒจไปฝ

$ docker run -td --name php7 --link db1:db1 ubuntu /bin/bash
$ docker ps

CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                 NAMES
2c52f1c58edb        ubuntu               "/bin/bash"              12 seconds ago      Up 11 seconds                             php7
dfc880ed429d        mysql/mysql-server   "/entrypoint.sh mysql"   10 minutes ago      Up 10 minutes       3306/tcp, 33060/tcp   db1

้€™้‚Š้ †ๅˆฉ็š„ๅปบ็ซ‹ไบ† php7 ้€™ๅ€‹ container,ไธฆไธ”ๅฐ‡ๅ…ถ link ๅˆฐ db1,ๆŽฅ่‘—่ฆไธ€้€ฃไธฒ็š„ๅฎ‰่ฃ php7 ไธฆไธ”ๅฏซไธ€ๅ€‹ pdo ๆธฌ่ฉฆ้€ฃ็ทš็š„ๆต็จ‹

$ docker exec -it php7 bash

$ env

# ๆ“ทๅ–้‡้ปž
DB1_PORT_3306_TCP_ADDR=172.17.0.2
DB1_PORT_3306_TCP_PROTO=tcp
SHLVL=1
HOME=/root
DB1_ENV_MYSQL_ROOT_PASSWORD=123456
DB1_PORT=tcp://172.17.0.2:3306
DB1_PORT_33060_TCP_PROTO=tcp
DB1_NAME=/php7/db1

$ apt-get udpate
$ apt-get install php php-mysql vim

$ vim test.php

test.php ็š„ๅ…งๅฎนๅฆ‚ไธ‹

<?php

$ip = getenv('DB1_PORT_33060_TCP_ADDR');
$dsn = "mysql:host=${ip};dbname=test";
$db = new PDO($dsn, 'root', 123456);
$sql = "SELECT * FROM `tests`";

foreach ($db->query($sql) as $value) {
    var_dump($value);
}

ๆŽฅ่‘—ๆˆ‘ๅ€‘ๅŸท่กŒ็œ‹็œ‹

$ php test.php

array(4) {
  ["id"]=>
  string(1) "1"
  [0]=>
  string(1) "1"
  ["name"]=>
  string(1) "a"
  [1]=>
  string(1) "a"
}
array(4) {
  ["id"]=>
  string(1) "2"
  [0]=>
  string(1) "2"
  ["name"]=>
  string(1) "b"
  [1]=>
  string(1) "b"
}

้€™ๆจฃๅฐฑๅคงๅŠŸๅ‘Šๆˆๅ•ฆ

docker-machine

docker ไธ€ๆฌกๅช่ƒฝ bind ไธ€ๅ€‹ๅฐๅค–็š„ 80 port,ๅฆ‚ๆžœ่ฆๅฏฆ็พไธๅŒ domain name ไธๅธถ port ๅŽปไธๅŒ็š„ container ้€™็จฎไฝœๆณ•,ๅ‰็ซฏ่ฆๆžถ่จญไธ€ๅ€‹ nginx ๅŽป่จญๅฎšๅฐŽๅ‘,้€™้‚Šๆไพ›ๅฆไธ€ๅ€‹ๅทๆ‡ถ็š„ๆ–นๆณ•,docker-machine ๆœฌ่บซ็”จ็š„ๅฐฑๆ˜ฏ vm,ๆ‰€ไปฅๆˆ‘ๅ€‘ๅฏไปฅ้–‹ๅฆไธ€ๅ€‹ vm,้€™ๆ™‚ๅ€™ๅฐฑๅพ—้€ฒๅˆฐ docker terminal,ๅŸท่กŒไปฅไธ‹ๆŒ‡ไปค

$ docker-machine create -d virtualbox chan

ๆŽฅ่‘—ๅŸท่กŒ

$ docker-machine ls

ๆˆ‘ๅ€‘ๆœƒ็œ‹ๅˆฐ

NAME      ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER    ERRORS
chan      -        virtualbox   Running   tcp://192.168.99.101:2376           v1.12.3
default   *        virtualbox   Running   tcp://192.168.99.100:2376           v1.12.3

ๆˆๅŠŸ็š„ๅปบ็ซ‹ไบ† chan ้€™ๅ€‹ vm,ๆˆ‘ๅ€‘ๅฏไปฅไฝฟ็”จ ssh ้€ฒๅŽป 192.168.99.101,ๅฆ‚ๆžœไฝ ๅœจ docker terminal ่ฆๅˆ‡ๆ›็’ฐๅขƒๅช่ฆๅŸท่กŒไธ‹ๆ–นๆŒ‡ไปคๅณๅฏ,็„ถๅพŒๆŠŠ lamp ็š„็’ฐๅขƒๅšๅœจ้€™ๅ€‹ ip ่ฃก้ข,ไธฆไธ”ๅœจๆœฌๆฉŸ่จญๅฅฝ hosts ้€ฃ้Žไพ†ๅณๅฏ

$ eval $(docker-machine env chan)

ๅฏไปฅๅฐ‡่‡ช่ฃฝ็š„ web image ๆ‹ท่ฒๅ‡บไพ†ไธฆๅฏซๆˆ Dockerfile,้€™ๆจฃ้–‹ไธ€ๅ€‹ vm ไธฆไธ”ๅปบไธ€ๅ€‹ๆ–ฐ็’ฐๅขƒ้žๅธธ็š„ๅฟซ,ๅฆ‚ๆžœๅชๆ˜ฏๆธฌ่ฉฆ็’ฐๅขƒไธๅœจๆ„ port ็š„่ฉฑๅฐฑ็”จไธๅŒ็š„ port ๅŽปๅฐŽๅ‘ๆฏๅ€‹ container,ๆˆ–่€…ๆ˜ฏ่ฆ็”จๅ“ชๅ€‹ case ๅฐฑ start ๅ“ชๅ€‹ container ไนŸๆ˜ฏ ok ็š„,ๅฆ‚ๆžœไฝ ่ทŸๆˆ‘ไธ€ๆจฃ้‡้–‹ๆฉŸๆˆ–้—œๆฉŸๆœƒๆŠŠ่ปŸ้ซ”้ƒฝ้—œไนพไนพๆทจๆทจ็š„่ฉฑ,ๅฏไปฅๅœจ docker toolbox terminal ไธ‹ๆŒ‡ไปค

$ docker-machine stop default

2016/11/20

Gulp Watch And Babel

็›ฎๅ‰ๆˆ‘ๅธธไฝฟ็”จ webpack ไพ†็ทจ่ญฏ JavaScript ๆช”ๆกˆ,ๅŒ…ๅซ babel ็š„็ทจ่ญฏ,็„ถ่€Œๆœ‰ๆ™‚ๅ€™ๆˆ‘ๅ€‘ๅฏ่ƒฝๅชๆƒณๅฏซๅฐๆฑ่ฅฟ,ไธ้œ€่ฆๆจก็ต„ๅŒ–,ไฝ†ๅˆๆƒณ่ฆ่‡ชๅ‹•ๅŒ–ๅตๆธฌไธฆไธ”ไฝฟ็”จ babel ็ทจ่ญฏ็š„่ฉฑ่ฉฒๆ€Ž้บผๅš,ไฝœๆณ•ๅพˆๅคš,ๆˆ‘้€™้‚ŠๆŽก็”จ็š„ๆ–นๅผๆ˜ฏไฝฟ็”จ gulp-watch ไพ†็›ฃ่ฝๆช”ๆกˆ่ฎŠๅ‹•,ๅตๆธฌๅˆฐๆ”น่ฎŠไปฅๅพŒไพฟ่‡ชๅ‹•็ทจ่ญฏ

gulp-babel

้ฆ–ๅ…ˆๆ˜ฏๅฎ‰่ฃๅฟ…่ฆ็š„ๅฅ—ไปถ

npm i --save-dev gulp-watch gulp-babel

gulp ๅ› ็‚บๅคชๅธธ็”จๆœฌ่บซๆˆ‘ๅฎ‰่ฃๅœจ global ไบ†,ไปŠๅคฉ็š„็ตๆง‹ๆ˜ฏ่ฆ็›ฃ่ฝ assets/js/src/ ไธ‹็š„ๆ‰€ๆœ‰็›ฎ้Œ„,ๅตๆธฌๅˆฐ่ฎŠๅ‹•ๅพŒ compile ๅˆฐ assets/js/build

gulpfile.js
const gulp = require('gulp');
const watch = require('gulp-watch');
const babel = require('gulp-babel');

gulp.task('babel', function() {
    watch('assets/js/src/**/*', function() {
        gulp.src('assets/js/src/**/*')
            .pipe(babel({
                presets: ['es2015']
            }))
            .pipe(gulp.dest('assets/js/build/'))
            .on('end', function() {
                console.log('file compiled!');
            });
    });
});

ๅŸท่กŒ gulp babelไพฟๆœƒ้–‹ๅ•Ÿ็›ฃ่ฝ,็•ถ compiled ๅฎŒๆˆๅพŒๆœƒ echo file compiled

babel-cli

้€™้‚Šๆไพ›ๅฆไธ€ๅ€‹ๆ–นๆณ•,ๅ› ็‚บ babel ๆœฌ่บซๅฐฑๆœ‰ cli ๅฏไปฅไฝฟ็”จ,ๆ‰€ไปฅๆˆ‘ๅ€‘ๅฏไปฅ็›ฃ่ฝๅพŒๆญ้… child_process ็š„ exec ไพ†ๅŸท่กŒ scripts

ๅฎ‰่ฃ babel-cli
npm i -g babel-cli
ๅขžๅŠ  package.json scripts ๆŒ‡ไปค
"scripts": {
    "babel": "babel assets/js/src/ -d assets/js/build/ --presets es2015"
}
gulpfile.js
const gulp = require('gulp');
const watch = require('gulp-watch');
const exec = require('child_process').exec;

gulp.task('babel', function() {
    watch('assets/js/src/**/*', function() {
        exec('npm run babel', function() {
            console.log('file complied');
        });
    });
});

2016/11/17

Query Log

sql ๅญ˜ๅ– log ๅฏไปฅ็”จไพ†ๆŸฅๅฐ‹ๆ‰€ๆœ‰็š„ๆ“ไฝœ่ปŒ่ทก,้€™้‚Šไฝฟ็”จ codeigniter ็š„ hooks,ไพ†้”ๆˆ่‡ชๅ‹•่จ˜้Œ„ query ็š„ๅŠŸ่ƒฝ。

่ณ‡ๆ–™ๅบซ

CREATE TABLE `query_logs` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`type` CHAR(10) NOT NULL,
`location` VARCHAR(255) NOT NULL,
`content` TEXT NOT NULL,
`admin_id` INT NOT NULL,
INDEX(`admin_id`),
`created_at` DATETIME NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;

type ็”จไพ†่จ˜้Œ„ sql ็š„่™•็†ๆ–นๅผ,ไพ‹ๅฆ‚่ชชๆ˜ฏ update ้‚„ๆ˜ฏ delete,content ็š„้ƒจๅˆ†ๅญ˜ๆ•ดๅฅ็š„่ชžๆณ•,admin_id ๆ˜ฏๆˆ‘ๅพŒๅฐ็š„็ฎก็†่€… id,ๆˆ‘้€™้‚Š็š„็ฏ„ไพ‹ๅชๆ‰“็ฎ—่จ˜้Œ„ๅพŒๅฐๆ“ไฝœ insert, update, delete ไธ‰็จฎ่กŒ็‚บ,ๆ‰€ไปฅๆˆ‘็”จ admin_id ็•ถไฝœๆ˜ฏๅฆ่ฆ่จ˜้Œ„็š„ไพๆ“š,ๅฆ‚ๆžœ่ฆๅšๆ›ด็ดฐ็š„่จญๅฎšๅฏไปฅๅ†่กŒ้…็ฝฎ。

่จญๅฎš

application/config/autoload.php
$autoload['libraries'] = array('database', 'session');
$autoload['config'] = array('site');
application/config/hooks.php
$hook['post_controller'] = [
    'class' => 'QueryLogger',
    'function' => 'save',
    'filename' => 'QueryLogger.php',
    'filepath' => 'hooks',
    'params' => ''
];
application/config/site.php
$config['query_types'] = [
    'insert',
    'update',
    'delete'
];

ๆˆ‘็›ฎๅ‰ๅช็ด€้Œ„ไบ†้€™ไธ‰ๅ€‹ไบ‹ไปถ,ๅฆ‚ๆžœๆœ‰ๅ…ถไป–้œ€ๆฑ‚ๅฏไปฅ้€้Ž config ๅขžๆธ›

Hook ๅŠŸ่ƒฝ

application/hooks/QueryLogger.php
<?php

if (!defined('BASEPATH')) exit('No direct script access allowed');

class QueryLogger
{
    private $ci;
    private $types;

    public function __construct()
    {
        $this->ci =& get_instance();
        $this->types = $this->ci->config->item('query_types');
    }

    public function save()
    {
        if ($this->can_saved()) {
            foreach ($this->ci->db->queries as $query) {
                $query = str_replace("\n", '', $query);
                $type = $this->get_type($query);

                if ($type !== '') {
                    $this->ci->db->insert('query_logs', [
                        'type' => $type,
                        'content' => $query,
                        'location' => $this->ci->router->fetch_class().'/'.$this->ci->router->fetch_method(),
                        'admin_id' => $this->ci->session->admin_id,
                        'created_at' => date('Y-m-d H:i:s')
                    ]);
                }
            }
        }

    }

    public function can_saved()
    {
        if (count($this->ci->db->queries) > 0 && $this->ci->session->has_userdata('admin_id')) {
            return true;
        }

        return false;
    }

    public function get_type($query)
    {
        return implode('', array_filter($this->types, function ($type) use ($query) {
            return stristr($query, $type);
        }));
    }
}

2016/11/11

First article from classeur

Blogger ๆ˜ฏๆˆ‘ไธ€็›ดไปฅไพ†ไฝฟ็”จ็š„ blog ่ปŸ้ซ”,ไน‹ๅ‰็š„ๆ’ฐๅฏซๆจกๅผๆ˜ฏๅœจๆœฌๆฉŸ markdown ็ทจ่ผฏๅพŒ,ๅŒฏๅ‡บๆˆ html ่ฒผไธŠ blogger,็„ถๅพŒ markdown ็š„ๅŽŸๆ–‡ๅ†ๅญ˜ๅˆฐ dropbox ๆˆ– evernote,ๅ› ๆญคๅ‡่จญๆˆ‘่ฆไฟฎๆญฃ้Œฏๅญ—,ๅฟ…้ ˆไฟฎๆ”น้›™้‚Š,ๆฒ’่พฆๆณ•,blogger ็”จ็ฟ’ๆ…ฃไบ†,ไฝ†ไป–ไธๆ”ฏๆด makdown,ไปŠๅคฉ็ˆฌๆ–‡ๆ‰พๅˆฐไบ† stackedit ๅฏไปฅ sync ๅˆฐๅธธ็”จ็š„็ฉบ้–“ๅฆ‚ dropbox ๆˆ– Google drive,้‚„ๅฏไปฅ็›ดๆŽฅ publish ๅˆฐ blogger,็ดขๆ€งๅฐฑ่ฉฆ็”จไบ†ไธ€ไธ‹,ไฝ†ไป–็š„ ux ๅ…ถๅฏฆๅพˆไธ็›ด่ฆบ,็ทจ่ผฏๆ™‚้‚„ๅกๅก็š„,่€Œไธ”ไป–ๆœ‰ๅ€‹่ถ…้€ฃ็ต้€ฃๅˆฐๆˆ‘็พๅœจๆญฃๅœจไฝฟ็”จ็š„ classeur,ๆˆ‘ๆ‡ท็–‘้‚ฃๅ€‹ๅฐˆๆกˆๆฒ’ๅœจ maintain ไบ†…

่ฝ‰้Žไพ†้€™้‚ŠไปฅๅพŒไฝฟ็”จไธŠ็œŸ็š„่ˆ’ๆœๅคšไบ†,้™คไบ† preview ๆœ‰ๆ™‚ๅ€™ๆœƒๅกๅก็š„ไปฅๅค–,่ตท็ขผไฝฟ็”จ็•Œ้ข่ทŸ็ทจ่ผฏๅทฅๅ…ท้‚„็ฎ—้ †ๆšข,publish ไนŸ้‚„่ ปๅฟซ็š„,ไน‹ๅพŒๆ‡‰่ฉฒๅฐฑๆœƒไฝฟ็”จ้€™ๅฅ—ไพ†ๆ’ฐๅฏซไบ†,ๅ…่ฒปๆ–นๆกˆๅฏไปฅๆ”พ็ฝฎ 100 ๅ‰‡ๆ–‡็ซ ,็ญ‰ๆœŸๆปฟ้‚„็ฎ—ๆปฟๆ„็š„่ฉฑๅ†ไป˜ๆœˆ่ฒป。

้ †ๅธถๆไธ€ไธ‹,ๆœ€่ฟ‘่ฟทไธŠ wiki,่‡ชๅทฑๆžถไบ†ไธ€ๅ€‹ไพ†็Žฉ,ไฝ†ไธ็Ÿฅ้“่ฆๅฏซไป€้บผ XD

My Wiki

2016/11/04

Codeigniter image_helper

ๅ‰่จ€

ไปŠๅคฉไป‹็ดนๅ…ฉๅ€‹็ธฎๅœ–็š„ helper,ไฝฟ็”จ็š„ๅฅ—ไปถๆ˜ฏ ImageWorkshop,ไปฅไธ‹้ข้€™ๅ…ฉๅผตๅœ–็‰‡่งฃ่ชช。

500x300

300x500

็จ‹ๅผ็ขผ

application/contollers/Image.php
<?php

class Image extends CI_Controller
{
    public function index()
    {
        $this->load->helper('image_helper');

        $this->load->view('image');
    }
}
application/helpers/image_helper.php
<?php

use PHPImageWorkshop\ImageWorkshop;

if (!function_exists('fit_thumb')) {
    function fit_thumb($path, $width = 150, $height = 0)
    {
        if (!file_exists($path)) {
            return 'assets/imgs/file_not_exists.png';
        }

        if ($height == 0) {
            $height = $ratio = $width;
        } else {
            $ratio = ($width < $height) ? $height : $width;
        }

        $paths = pathinfo($path);
        $thumbName = "{$paths['filename']}_fit_{$width}x{$height}.{$paths['extension']}";
        $thumbPath = $paths['dirname'].'/thumb/';
        $fullThumbPath = $thumbPath.$thumbName;

        if (file_exists($fullThumbPath)) {
            return $fullThumbPath;
        }

        $layer = ImageWorkshop::initFromPath($path, true);
        $layer->resizeByLargestSideInPixel($ratio, true);

        $layer->cropInPixel($width, $height, 0, 0, 'MT');
        $layer->save($thumbPath, $thumbName);

        return $fullThumbPath;
    }
}

if (!function_exists('thumb')) {
    function thumb($path, $ratio = 150, $bySide = 'large')
    {
        if (!file_exists($path)) {
            return 'assets/imgs/file_not_exists.png';
        }

        $paths = pathinfo($path);

        switch ($bySide) {
            case 'large':
                $thumbName = "{$paths['filename']}_thumb_large_{$ratio}.{$paths['extension']}";
                break;
            case 'narrow':
                $thumbName = "{$paths['filename']}_thumb_narrow_{$ratio}.{$paths['extension']}";
                break;
        }

        $thumbPath = $paths['dirname'].'/thumb/';
        $fullThumbPath = $thumbPath.$thumbName;

        if (file_exists($fullThumbPath)) {
            return $fullThumbPath;
        }

        $layer = ImageWorkshop::initFromPath($path, true);

        switch ($bySide) {
            case 'large':
                $layer->resizeByLargestSideInPixel($ratio, true);
                break;
            case 'narrow':
                $layer->resizeByNarrowSideInPixel($ratio, true);
                break;
        }

        $layer->save($thumbPath, $thumbName);

        return $fullThumbPath;
    }
}

if (!function_exists('img_upload')) {
    function img_upload($path = '/', $image = '', $maxWidth = 3000)
    {
        $status = 'done';
        $message = '';
        $allows = ['jpeg', 'png', 'gif'];
        $file = $_FILES[$image];
        $fileName = $file['name'];
        $ext = pathinfo($fileName, PATHINFO_EXTENSION);
        $newName = date('YmdHis').rand(1000, 9999).'.'.$ext;
        $map = function ($item) {
            return "image/{$item}";
        };

        try {
            if (empty($fileName)) {
                throw new Exception('่ซ‹้ธๆ“‡ๆช”ๆกˆ');
            }

            $type = $file['type'];
            $tmpName = $file['tmp_name'];

            if (!in_array($type, array_map($map, $allows))) {
                throw new Exception('ๆช”ๆกˆๆ ผๅผ้Œฏ่ชค,ๅƒ…ๆŽฅๅ—'.implode(', ', $allows));
            }

            $layer = ImageWorkshop::initFromPath($tmpName, true);
            list($width, $height) = getimagesize($tmpName);

            if ($width > $maxWidth) {
                $layer->resizeInPixel($maxWidth, null, true);
            }

            $layer->save($path, $newName);
        } catch (Exception $e) {
            $status = 'fail';
            $message = $e->getMessage();
        }

        return [
            'status' => $status,
            'image' => $newName,
            'message' => $message,
        ];
    }
}

if (!function_exists('image_delete')) {
    function image_delete($path, $image)
    {
        $path = rtrim($path, '/').'/';
        @unlink($path.$image);
        $fileName = pathinfo($image, PATHINFO_FILENAME);
        $thumbPath = $path.'thumb/';
        $thumbs = directory_map($thumbPath);

        foreach ($thumbs as $thumb) {
            $body = explode('_', $thumb)[0];

            if ($body === $fileName) {
                @unlink($thumbPath.$thumb);
            }
        }
    }
}
application/views/image.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Image Helper</title>
</head>
<body>
    <h3>500x300</h3>
    <img src="<?php echo $landscape; ?>">
    <h3>300x500</h3>
    <img src="<?php echo $portrait; ?>">

    <h3>fit_thumb</h3>
    <img src="<?php echo fit_thumb($landscape, 150); ?>">
    <img src="<?php echo fit_thumb($landscape, 150, 200); ?>">
    <img src="<?php echo fit_thumb($portrait, 150); ?>">
    <img src="<?php echo fit_thumb($portrait, 200, 150); ?>">

    <h3>thumb</h3>
    <img src="<?php echo thumb($landscape, 150); ?>">
    <img src="<?php echo thumb($landscape, 150, 'narrow'); ?>">
    <img src="<?php echo thumb($portrait, 150); ?>">
    <img src="<?php echo thumb($portrait, 150, 'narrow'); ?>">
</body>
</html>

Demo

fit_thumb

fit_thumb ๅฆ‚ๆžœๆฒ’ๆœ‰ๅธถๅ…ฅ็ฌฌไธ‰ๅ€‹ๅƒๆ•ธไพฟๆœƒๆ“ทๅ–่ฉฒๅœ–ๅฝข็‚บๆญฃๆ–นๅฝข,ๅฆ‚ๆžœๆœ‰ๅธถๅ…ฅ็š„่ฉฑไพฟๆœƒ็…งๆฏ”ไพ‹ๆ“ทๅ–。

500x300

fit_thumb($landscape, 150)

150x150

fit_thumb($landscape, 150, 200)

150x200

300x500

fit_thumb($portrait, 150)

150x150

fit_thumb($portrait, 200, 150)

200x150

thumb

thumb ๅŠŸ่ƒฝๆœƒไพ็…งๅ‚ณๅ…ฅ็š„ๆฏ”ไพ‹ๅƒๆ•ธๅฐ‡ๅœ–็‰‡ไพ็…งๅƒๆ•ธ็ญ‰ๆฏ”ไพ‹็ธฎๆ”พ,็ฌฌไบŒๅ€‹ๅƒๆ•ธๅฏไปฅๆฑบๅฎšๅพžๅฏฌ้‚Š้‚„ๆ˜ฏ็ช„้‚Šๅš็ธฎๆ”พ

500x300

thumb($landscape, 150)

150x90

thumb($landscape, 150, 'narrow')

250x150

300x500

thumb($portrait, 150)

90x150

thumb($portrait, 150, 'narrow')

150x250

img_upload

img_upload ้€™ๅ€‹ function ๅฏไปฅๅฐ‡ไฝ ไธŠๅ‚ณ็š„ๅœ–็‰‡็ธฎๅœ–ๅพŒๅญ˜ๅ…ฅ,ไธ€่ˆฌไพ†่ชช็ถฒ้ ๆœƒ้กงๆ…ฎ็š„ๆ˜ฏๅฏฌไธ่ฆ็ ดๅฃž,ๅ› ๆญค็จ‹ๅผ็ขผๆœƒไปฅๅฏฌๅบฆ็‚บไธปไพ†ๅš็ธฎๅœ–。

2016/11/01

Codeigniter file_manager helper

ๆช”ๆกˆไธŠๅ‚ณๆ˜ฏ่ ปๅธธไฝฟ็”จ็š„ๅŠŸ่ƒฝ,ci ่ฃก้ขๆœ‰ๅ…งๅปบๆช”ๆกˆไธŠๅ‚ณ็š„ๅŠŸ่ƒฝ,ไฝ†ๆˆ‘ๅ€‘็•ถ็„ถไธๆƒณ่จ˜ๅพ—็น่ค‡็š„ๅ‘ผๅซๆ–นๅผ,ๅฏซๆˆ helper ไพ†ไฝฟ็”จๆ˜ฏๆœ€ๆ–นไพฟ็š„,ไปŠๅคฉ news ็•ถไฝœ็ฏ„ไพ‹็คบ็ฏ„ไธ€ไธ‹ๅฏซๆณ•。

news table
CREATE TABLE `news` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(50) NOT NULL,
`file_name` VARCHAR(100) NOT NULL,
`real_name` VARCHAR(100) NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
application/controllers/News.php
class News extends CI_Controller
{
    public function index()
    {
        $this->load->helper('form');
        $this->load->view('news');
    }

    public function save()
    {
        $this->load->database();
        $this->load->helper('file_manager');
        $data = [];

        if (has_upload('file')) {
            $upload = file_upload('file', 'assets/uploads/news');

            if ($upload['status'] == 'fail') {
                die($upload['message']);
            } else {
                $data['file_name'] = $upload['fileName'];
                $data['real_name'] = $upload['realName'];
            }
        }

        $data['name'] = uniqid();
        $this->db->insert('news', $data);
    }

    public function download($id)
    {
        $this->load->database();
        $this->load->helper('file_manager');
        $row = $this->db->get_where('news', ['id' => $id])->row_array();

        force_download("assets/uploads/news/{$row['file_name']}", $row['real_name']);
    }
}

index method ๅฐฑๆ˜ฏ็ฐกๅ–ฎ็š„ๅปบ็ซ‹ไธ€ๅ€‹่กจๅ–ฎ,ๅ‚ณ้€ name ่ทŸ file ้€™ๅ…ฉ็š„ field ๅˆฐ save ๅ„ฒๅญ˜,้€™้‚Šๅš็š„้ƒฝๆ˜ฏๆœ€็ฐกๅ–ฎ็š„็คบ็ฏ„,ๅฏฆ้š›ๆƒ…ๆณ้‚„ๆ˜ฏ่ณ‡็…ง้œ€ๆฑ‚ๅŽปไฟฎๆ”น,ไฝ†ๅ›žๅ‚ณ็š„ๅ…งๅฎนๆ‡‰่ฉฒ้ƒฝๅฏไปฅๆ‡‰ไป˜ๅ…ถไป–็š„ๆขไปถ,download ็š„้ƒจไปฝๅฐฑๆ˜ฏ่ชฟ็”จ file_manager helper ไธ‹่ผ‰ๅŽŸๅง‹็š„ๆช”ๆกˆ,่‹ฅ้žๅฟ…่ฆ,็›ก้‡ไธ่ฆๅœจ helper ่ฃก้ขๅš db connection,ๅ› ็‚บ helper ๅพˆๆœ‰ๅฏ่ƒฝๆœƒๅœจ่ฟดๅœˆ่ฃก้ขๅ‡บ็พ,้€™ๆจฃ db query ๆ•ธ้‡ๆœƒ้šจ่ณ‡ๆ–™้‡ๅขžๅŠ 。

application/views/news.php
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>News</title>
    </head>
    <body>
        <?php echo form_open_multipart('news/save'); ?>
        <?php echo form_input('name', uniqid()); ?>
        <?php echo form_upload('file'); ?>
        <?php echo form_submit('go', 'go'); ?>
        <?php echo form_close(); ?>
    </body>
</html>

news ็š„ view,็ฐกๅ–ฎ็š„ไฝฟ็”จ form helper ็”Ÿๆˆ。

application/helpers/file_manager_helper.php
if (!function_exists('file_upload')) {
    function file_upload($file, $path, array $allows = [])
    {
        $ci =& get_instance();
        $status = 'done';
        $message = '';
        $fileName = '';
        $realName = '';
        $config['upload_path'] = $path;
        $config['allowed_types'] = (count($allows) > 0) ? implode('|', $allows) : '*';
        $config['encrypt_name'] = true;
        $ci->load->library('upload', $config);

        if (!$ci->upload->do_upload($file)) {
            $message = $ci->upload->display_errors();
            $status = 'fail';
        } else {
            $fileData = $ci->upload->data();
            $fileName = $fileData['file_name'];
            $realName = $fileData['client_name'];
        }

        return compact('status', 'message', 'fileName', 'realName');
    }
}

if (!function_exists('force_download')) {
    function force_download($path, $realName)
    {
        $originFile = urlencode($realName);
        $realFile = $path;

        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Content-Type: application/force-download");
        header("Content-Disposition: attachment; filename=".$originFile);
        header("Content-Description: File Transfer");
        @readfile($realFile);
    }
}

if (!function_exists('has_upload')) {
    function has_upload($file)
    {
        if (isset($_FILES[$file]) && is_uploaded_file($_FILES[$file]['tmp_name'])) {
            return true;
        }

        return false;
    }
}

file_upload function ่ชฟ็”จไบ† upload ็š„ library,ๅ› ็‚บไธป่ฆๆ˜ฏๅ‚ณๆช”ๆกˆ,ๆ‰€ไปฅ้ ่จญ allows ็‚บๅ…จ้ƒจ,็•ถ็„ถไนŸๆœ‰ๅ…ˆๅฏซๅฅฝๅƒๆ•ธๅฏไปฅๅ‚ณ้ž,ๅฐ่ฑกไธญ codeigniter ็š„ไธŠๅ‚ณๆœƒๆชขๆŸฅ mime,ๆ‰€ไปฅ allow ็š„ๅ…งๅฎนๅฏ่ƒฝ่ฆ็ฌฆๅˆ mime ็š„ๆช”ๅ่ฆ็ฏ„,ๅฆ‚ๆžœ่ฆไธŠๅ‚ณ็š„ๆ˜ฏๅœ–็‰‡็š„ๆฑ่ฅฟ,ๅฏไปฅ็”จ้€™ๅ€‹ function ๅŽปๆ”นๅ‡บไธ€ๅ€‹ image_upload ็š„ function,ๅ†ๆŠŠ่ทŸๅœ–็‰‡ๆฏ”่ผƒๆœ‰้—œ้€ฃ็š„ๅ…งๅฎนๆ”พ้€ฒๅŽป,ๅœจไธŠๅ‚ณ็š„ๆ™‚ๅ€™ๆˆ‘ๅ€‘ๆœƒๅฐ‡ๆช”ๅไฝฟ็”จ่‹ฑๆ–‡็ทจ็ขผไปฃๆ›ฟ,ไฝ†ๅŽŸๅง‹็š„ๆช”ๅๆœƒไธ€่ตทๅญ˜ๅˆฐ database,ๅœจๅพˆๅคš Linux server ๆช”ๆกˆๅ็จฑไฝฟ็”จ้ž่‹ฑๆ–‡็š„่ฉฑๆœƒ็„กๆณ•่ฎ€ๅ–,ๆ‰€ไปฅๆœ€ๅฅฝๆ˜ฏ็”จ็ด”่‹ฑๆ•ธๅŽปๅ„ฒๅญ˜ๆช”ๆกˆ,ๅ› ็‚บ codeigniter ็š„ input helper ๆœฌ่บซๆฒ’ๆœ‰ๆ”ฏๆด file ็š„ๅ…งๅฎน,ๆ‰€ไปฅๅฏซไบ†ไธ€ๅ€‹ has_upload ็š„ function ไพ†ๆชขๆŸฅ้€™ๆฌก็š„ๅ‚ณ่ผธๆœ‰ๆฒ’ๆœ‰ไธŠๅ‚ณๆช”ๆกˆ。

force_download ้€™ๅ€‹ function ๅช่ฆๅฐ‡ๆช”ๆกˆไฝ็ฝฎ่ทŸๅŽŸๅง‹ๆช”ๅๅธถๅ…ฅ,ไพฟๅฏไปฅไธ‹่ผ‰ๅŽŸๅง‹็š„ๆช”ๆกˆ,ๅณไพฟๆ˜ฏไธญๆ–‡ไนŸๆฒ’ๅ•้กŒ。