學習使用 MySQL 視圖、儲存過程、觸發器、事件用法

透過 MySQL 本身提供的視圖、儲存過程、觸發器、事件,可以讓程式開發時更簡易,因為可以將一些工作直接交由 MySQL 去處理,不過在使用時,要注意是否會消耗掉太多資料庫主機的效能。

先做記錄,慢慢補吧….


 

視圖 View

簡介:

使用時機:


 

儲存過程 Procedure

簡介:

使用時機:


 

觸發器 Trigger

簡介:

使用時機:


 

事件 Event

簡介:

使用時機:

簡單解釋工程師開發如何達成自動化的測試、整合及佈署到正式的客戶環境

Continuous Deployment via GitLab, Jenkins, Docker and Slack
簡單解釋工程師開發如何達成自動化的測試、整合及佈署到正式的客戶環境

在開始之前先簡單介紹一些工具:

Git

程式碼版本控制系統

ben@ben-UX305CA:~/docker/fju_ehs/httpd$ git branch
* bendev
  master

簡單解釋:主要支幹是 master,如果有多個程式設計師一同開發或是要修復 bug 時,可以暫時先開另一個分支,最後在合併回主支,並且可以隨時切換到不同版本的程式碼,最重要的是可以推送到遠端進行備份,而其它程式設計師透過 git 取得程式時也會一併取得相關的版本。

 

GitHub

https://zh.wikipedia.org/wiki/GitHub

GitHub是一個透過Git進行版本控制的軟體原始碼代管服務,由GitHub公司的開發者Chris Wanstrath、PJ Hyett和Tom Preston-Werner使用Ruby on Rails編寫而成。 GitHub同時提供付費帳戶和免費帳戶。

https://github.com/ 

 

GitLab

https://zh.wikipedia.org/wiki/Gitlab

GitLab是一個利用Ruby on Rails開發的開源應用程式,實現一個自代管的Git專案倉庫,可通過Web介面進行存取公開的或者私人專案。
它擁有與GitHub類似的功能,能夠瀏覽原始碼,管理缺陷和注釋。可以管理團隊對倉庫的存取,它非常易於瀏覽提交過的版本並提供一個檔案歷史庫。團隊成員可以利用內建的簡單聊天程式(Wall)進行交流。它還提供一個代碼片段收集功能可以輕鬆實現代碼復用,便於日後有需要的時候進行尋找。

 

Virtual Box

虛擬機軟體,你可能要先了解全虛擬化與半虛擬化技術

快速理解:半虛擬化需要透過客戶端的作業系統模擬,Virtual Box 為半虛擬化

https://www.virtualbox.org/

20170910-02

圖片來源:https://www.google.com.tw/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&cad=rja&uact=8&ved=0ahUKEwjp86ym9prWAhXJi7wKHe6ABUMQjRwIBw&url=https%3A%2F%2Fwww.virtualbox.org%2Fmanual%2Fch01.html&psig=AFQjCNGkl112MXsS9Qcwv–TCnbC_JiFKQ&ust=1505143413034495

 

Vagrant

https://www.vagrantup.com/

文字化(終端機)版本的 Virtual Box 腳本控制程式

20170910-03

圖片來源:https://css-tricks.com/wp-content/uploads/2015/05/command-line.png

 

Docker

虛擬機容器技術

可以參考這裡:http://www.ithome.com.tw/news/91847

 

Docker Hub

公開的 Docker Image 庫

https://hub.docker.com/ 

 

Docker Registry

自建私有的 Docker Image 庫

 

Slack

工程師版本的 Line,可串接程式、建立程式自動通知訊息的流程,發生錯誤第一時間知道

https://slack.com/ 

 

Jenkins

https://jenkins.io/ 

Jenkins是一個用Java編寫的開源持續整合工具。在與Oracle發生爭執後,專案從Hudson專案復刻

Jenkins提供了軟體開發的持續整合服務。它執行在Servlet容器中(例如Apache Tomcat)。它支援軟體配置管理(SCM)工具(包括AccuRev SCMCVSSubversionGitPerforceClearcaseRTC),可以執行基於Apache AntApache Maven的專案,以及任意的Shell指令碼和Windows批次處理命令。Jenkins的主要開發者是川口耕介。[2]Jenkins是在MIT許可證下發布的自由軟體[3]

可以通過各種手段觸發構建。例如提交給版本控制系統時被觸發,也可以通過類似Cron的機制排程,也可以在其他的構建已經完成時,還可以通過一個特定的URL進行請求。

https://zh.wikipedia.org/wiki/Jenkins_(%E8%BD%AF%E4%BB%B6)

20170910-01圖片來源:https://medium.com/@ahmetatalay/continous-deployment-via-gitlab-jenkins-docker-and-slack-5d08836d01e0

 

使用上面所介紹的工具達成CI/CD自動化發佈或部署 (Continuous Delivery / Continuous Deployment)

基本上透過上述的工具,可以達成 CI/CD 自動化發佈或部署,減少人工重複建立環境及測試的工作。

 

什麼是CI/CD自動化發佈或部署 (Continuous Delivery / Continuous Deployment)

自動化發佈或部署,就是要讓所有工程師只要上傳程式碼後,CI/CD Server會自動幫程式碼做測試、建立虛擬機環境,並回傳成功或失敗的訊息給所有相關的專案人員。

除了可以大大的減少以往人工的重複作業外,也可以讓每個參與專案的人可以在第一時間取得相同的訊息。

 

為什麼要使用CI/CD自動化發佈或部署 (Continuous Delivery / Continuous Deployment)

程式設計師每 push 一次程式碼,CI/CD Server會自動建置一台主機,並測試程式設計師的程式碼,透過不斷的出現小錯誤,讓程式設計師可以第一時間處理,來避免傳統專案直到最後發佈程式碼時才出現一堆主機系統環境錯誤,甚至要花好幾天才能解決。

而且透過 CI/CD Server 所自動建置的網站,到了一定的開發階段後,可以傳給客戶操作,除了可以讓客戶知道整個專案進度外,也可以讓客戶在第一時間反應心得,同樣可避免傳統上要等到6個月其至1年才讓客戶看到結果,但卻發現客戶要的不是這個。

 

對專案經理人來講,了解這些有什麼用處?

專案經理人了解上述技術、工具後 (當然前提是公司的技術主管導入了Scrum敏捷開發方式 ),透過上述工具,可以讓公司內部的專案經理及其它人第一時間知道專案進度,讓專案經理及管理階層的人在調派工作時,不會只憑感覺調派工作,而且可以避免長時間的與專案脫離。而每個參考專案開發的程式人員,也可以清楚知道目前專案的進度,對於時程的預估比較不會出現重大的誤判。

PHP將boolean值轉字串

如果有需要將 boolean 的值轉成字串,好方便使用如 in_array() 來判斷的話,可以使用下列方式

$a = true;
$b = false;

$array = [];

$array[] = $a ? 'true' : 'false';
$array[] = $b ? 'true' : 'false';

print_r($array);

結果:

Array ( [0] => true [1] => false )

前台純靜態網頁如何傳遞參數

直接範例如下:
假設有個商品列表頁面,提供各個商品的詳細頁面連結

http://learn.ben.docker/html_pass/index.html

進入該連結後,由 JS 取得網址參數 id

http://learn.ben.docker/html_pass/detail.html?id=1

如果在 detail.html 可以取得 id,接下來就可以透過 axios 來 get 遠端資料並顯示


index.html 程式碼:

<!DOCTYPE html>
<html>
<head>
	<title>影片列表頁面</title>
	<style type="text/css">
		a { margin-right: 10px; }
	</style>
</head>
<body>
	<h1>影片列表頁面</h1>

	<div id="app">
		<a :href="'./detail.html?id=' + film.id" v-for="film in films">{{ film.name }}</a>
	</div>

</body>
</html>
<script src="https://unpkg.com/vue"></script>
<script>
	var app = new Vue({
		el: '#app',
		data: {
			films: [
				{ id: 1, name: '影片1' },
				{ id: 2, name: '影片2' },
				{ id: 3, name: '影片3' },
				{ id: 4, name: '影片4' },
				{ id: 52, name: '影片52' }
			]
		}
	})
</script>

顯示結果:
影片列表頁面
影片1影片2影片3影片4影片52


detail.html 程式碼:

<!DOCTYPE html>
<html>
<head>
	<title>影片詳細介紹頁面</title>
</head>
<body>
	<h1>影片詳細介紹頁面</h1>
	<p><a href="./index.html">回首頁</a></p>

	<div id="app">
		{{ id }}
	</div>

</body>
</html>
<script src="https://unpkg.com/vue"></script>
<script>
	var app = new Vue({
		el: '#app',
		data: {
			id: null
		},
		created () {
			this.fetchData()
		},		
		methods: {
			fetchData() {
				this.id = window.location.search.slice(4);
			}
		}
	})
</script>

顯示結果:
影片詳細介紹頁面
回首頁
52

簡易開發API範例並測試

以下是 Server API 端的程式碼:

$verb = $_SERVER['REQUEST_METHOD'];

if($verb == 'GET')
{
	if(isset($_GET['filename']))
	{
		$file_content = file_get_contents($_GET['filename']);
		echo $file_content;
	}
	else
	{
		die('ERROR: REQUIRED PARAMETERS NOT GIVEN!');
	}
}
elseif($verb == 'POST')
{
	if(isset($_POST['filename']) and isset($_POST['content']))
	{
		file_put_contents($_POST['filename'], $_POST['content']);
	}
	else
	{
		die('ERROR: REQUIRED PARAMETERS NOT GIVEN!');		
	}
}
elseif($verb == 'DELETE')
{
	parse_str(file_get_contents('php://input'), $_DELETE);
	if(isset($_DELETE['file']))
	{
		if(file_exists($_DELETE['file']))
		{
			unlink($_DELETE['file']);
		}
	}
	else
	{
		die('ERROR: REQUIRED PARAMETERS NOT GIVEN!');
	}
}

然後我們可以透過 cURL 或 Chrome 的擴充功能 Advanced REST client 來測試上面的 API 程式。
2017-07-21 10-28-03 的螢幕擷圖

如何自訂 HTTP header 的值並取值

HTTP 超文本傳輸協定區分 header 和 body 兩個部份,我們可以使用下列方式單獨取出 header 來查看

ben@ben-UX305CA:~$ curl --head https://jsonplaceholder.typicode.com/posts/1
HTTP/1.1 200 OK
Date: Fri, 21 Jul 2017 02:09:10 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 292
Connection: keep-alive
Set-Cookie: __cfduid=d202b5717ee9bfe89c339aa98c18de2141500602950; expires=Sat, 21-Jul-18 02:09:10 GMT; path=/; domain=.typicode.com; HttpOnly
X-Powered-By: Express
Vary: Origin, Accept-Encoding
Access-Control-Allow-Credentials: true
Cache-Control: public, max-age=14400
Pragma: no-cache
Expires: Fri, 21 Jul 2017 06:09:10 GMT
X-Content-Type-Options: nosniff
Etag: W/"124-yiKdLzqO5gfBrJFrcdJ8Yq0LGnU"
Via: 1.1 vegur
CF-Cache-Status: HIT
Server: cloudflare-nginx
CF-RAY: 381a9dd9de540d73-SJC

如果我們自己開發 API 時,但又希望只有擁有合法的 API KEY 的使用者才能使用該 API,我們可以自訂 header 參數,把 API KEY 加到 header 裡面。

以下是 client 端的程式碼:

$url = 'http://172.17.0.11/apikey/';
// $query = urlencode('where={"steps":9243}');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt(
    $ch, 
    CURLOPT_HTTPHEADER,
    array(
        'X-Parse-Application-Id: myApplicationID',
        'X-Parse-REST-API-Key: myRestAPIKey',
        'Content-Type: application/json'
    )
);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);

echo $result;

再來我們可以在該 API 頁面先做簡單測試,看可不可以取得自訂的 header,因為 apache 版本的關係,建議使用方法1 比較方便。

以下是 Server API 端的程式碼:

方法1:

$header = apache_request_headers();
echo '<pre>';
print_r($header);
echo '</pre>';
die();

方法1 結果:

Array
(
    [Host] => 172.17.0.11
    [Accept] => */*
    [X-Parse-Application-Id] => myApplicationID
    [X-Parse-REST-API-Key] => myRestAPIKey
    [Content-Type] => application/json
)

方法2:

echo '<pre>';
print_r($_SERVER);
echo '</pre>';
die();

方法2 結果:(注意-變成_,且前面自動加入HTTP)

Array
(
    [HTTP_HOST] => 172.17.0.11
    [HTTP_ACCEPT] => */*
    [HTTP_X_PARSE_APPLICATION_ID] => myApplicationID
    [HTTP_X_PARSE_REST_API_KEY] => myRestAPIKey
    [CONTENT_TYPE] => application/json
    [PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    [SERVER_SIGNATURE] => 
Apache/2.2.15 (CentOS) Server at 172.17.0.11 Port 80


    [SERVER_SOFTWARE] => Apache/2.2.15 (CentOS)
    [SERVER_NAME] => 172.17.0.11
    [SERVER_ADDR] => 172.17.0.11
    [SERVER_PORT] => 80
    [REMOTE_ADDR] => 172.17.0.11
    [DOCUMENT_ROOT] => /var/www/html
    [SERVER_ADMIN] => root@localhost
    [SCRIPT_FILENAME] => /var/www/html/apikey/index.php
    [REMOTE_PORT] => 45894
    [GATEWAY_INTERFACE] => CGI/1.1
    [SERVER_PROTOCOL] => HTTP/1.1
    [REQUEST_METHOD] => GET
    [QUERY_STRING] => 
    [REQUEST_URI] => /apikey/
    [SCRIPT_NAME] => /apikey/index.php
    [PHP_SELF] => /apikey/index.php
    [REQUEST_TIME_FLOAT] => 1500603476.817
    [REQUEST_TIME] => 1500603476
)

一旦可以順利取得值後,我們就可以用來判斷是否有權限來執行該 API,甚至可以利用資料庫來增加 API KEY 的使用期限,一旦過期就無法使用等功能。

簡介cURL綜合傳輸工具

cURL是一個利用URL語法在命令列下工作的檔案傳輸工具,1997年首次發行。它支援檔案上傳和下載,所以是綜合傳輸工具,但按傳統,習慣稱cURL為下載工具。cURL還包含了用於程式開發的libcurl。
cURL支援的通訊協定有FTP、FTPS、HTTP、HTTPS、TFTP、SFTP、Gopher、SCP、Telnet、DICT、FILE、LDAP、LDAPS、IMAP、POP3、SMTP和RTSP。
libcurl支援的平台有Solaris、NetBSD、FreeBSD、OpenBSD、Darwin、HP-UX、IRIX、AIX、Tru64、Linux、UnixWare、HURD、Windows、Symbian、Amiga、OS/2、BeOS、Mac OS X、Ultrix、QNX、BlackBerry Tablet OS、OpenVMS、RISC OS、Novell NetWare、DOS等。
來源:https://zh.wikipedia.org/wiki/CURL

另外我們可以使用 JSONPlaceholder 工具網站來測試 REST API
Fake Online REST API for Testing and Prototyping
https://jsonplaceholder.typicode.com/

取得所有資料

curl https://jsonplaceholder.typicode.com/posts

取得一筆資料

curl https://jsonplaceholder.typicode.com/posts/1

取得一筆資料(含header部份)

curl -i https://jsonplaceholder.typicode.com/posts/1

只取header部份

curl --head https://jsonplaceholder.typicode.com/posts/1

只取header部份

curl -I https://jsonplaceholder.typicode.com/posts/1

取得資料並儲存到 test.txt

curl -o test.txt https://jsonplaceholder.typicode.com/posts/3

下載檔案(檔名為參數 3)

curl -O https://jsonplaceholder.typicode.com/posts/3

也可以下載其它檔案(如圖檔)

curl -O http://i.imgur.com/QRlAg0b.png

使用 REST API POST 資料

curl --data "title=Hello&body=Hello World" https://jsonplaceholder.typicode.com/posts

使用 REST API PUT 修改資料(每一個欄位 -d key=value)

curl -X PUT -d title=Hello https://jsonplaceholder.typicode.com/posts/3

使用 REST API DELETE 刪除一筆資料

curl -X DELETE https://jsonplaceholder.typicode.com/posts/3

使用帳號密碼登入有保護的網站位置並取得資料

curl -u test:1234 http://172.17.0.11/lock

有些網站具有跳轉,如下列會返回301或302,無法取得真正檔案資料

curl http://google.com

加上參數 -L 會跟隨跳轉,取得真正位置的檔案資料

curl -L http://google.com

使用 cURL 來登入 FTP 並上傳一個檔案

curl -u test@abc.com:1234 -T hello.txt ftp://ftp.abc.com

使用 cURL 來登入 FTP 並下載一個檔案

curl -u test@abc.com:1234 -O ftp://ftp.abc.com/hello.txt

Laravel 5.4 目錄比對

    public function show($id)
    {
        $web = Web::find($id);

        $dt = Carbon::now();
        $timestamp = $dt->timestamp;
        $directories = File::directories('/var/www/html');

        $pattern = '/' . addcslashes($web->name, '-') . '$/';
        // $pattern = '/myci32-8$/';

        $matches = preg_grep($pattern, $directories);

        $path = '/var/www/html/' . $web->name;
        if(File::exists($path))
        {
            $check = '已經有這個目錄';
        }
        else
        {
            $check = '沒有這個目錄';
        }

        // 取得流量記錄
        $extends = Extend::where('web_id', $web->id)->get();

        return view('webs.show',
            compact('web', 'timestamp', 'directories', 'matches', 'pattern', 'path', 'check', 'extends'));
    }

結果:

時間戳記:
1498548347
系統目錄:
/var/www/html/backup
/var/www/html/tongtong
/var/www/html/myci3-1
/var/www/html/myci3-5
/var/www/html/myci3-6
/var/www/html/myci3-3
/var/www/html/myci3-2
/var/www/html/myci3-4
/var/www/html/myci3-8
/var/www/html/smws
/var/www/html/sweet_to_die

正規化條件:
/sweet_to_die$/
正規化比對結果:
有符合
array(1) {
[11]=>
string(26) “/var/www/html/sweet_to_die"
}

Path: /var/www/html/sweet_to_die
已經有這個目錄

允許mysql的遠端連線

如果無法連線遠端資料庫時(不同 docker container 裡的資料庫),應該是mysql 沒有允許遠端連線,進入該伺服器中的 mysql 終端機,下達以下指令。

root@127.0.0.1 代表 root 帳號只允許 127.0.0.1

root@% 代表 root 帳號允許所有位置(本機和任何遠端)


GRANT ALL ON *.* to root@'%' IDENTIFIED BY '1234';

刷新權限表


flush privileges;

這樣我們就可以在本機端使用 HeidiSQL 軟體登入不同 IP 的 container 裡的資料庫系統,或是使用終端機方式登入。

mysql -uroot -p1234 -h 172.17.0.16

Docker stop 後,restart 時,要再進入容器中再重啟服務

在本機端使用 Docker 開發時,要注意如果 stop container 後,可能會造成容器中的服務出錯,需要在重啟容器後,進入容器再重啟該服務。

ben@ben-UX305CA:~/docker$ docker exec -ti ben_centos69 bash
[root@ed4204fc441e /]# service httpd status
httpd dead but pid file exists
[root@ed4204fc441e /]# service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]
[root@ed4204fc441e /]# service mysqld restart
Stopping mysqld:                                           [FAILED]
Starting mysqld:                                           [  OK  ]
[root@ed4204fc441e /]# service mysqld restart
Stopping mysqld:                                           [  OK  ]
Starting mysqld:                                           [  OK  ]
[root@ed4204fc441e /]#

至於為什麼會 stop 或 restart,因為不是在正式環境中佈署,而是在開發機上操作,有時會面臨重開電腦的需求。