執行:
http://sandbox.onlinephpfunctions.com/code/8349c158d68cdf644dd07d802f3782384fb4e7b7
使用範例:
加密的密碼
$salt = '11223344';
// 需要傳遞的陣列
$codevalue_array = array(
'Amt' => '111',
'MerchantOrderNo' => 'ertgyhujioiuytre'
);
// 打包產生需要的資料
$send_code = jwtenc($salt,$codevalue_array);
var_dump($send_code);
// 把回傳回來的資料驗證解碼
$codevalue = jwtdec($salt,$send_code);
var_dump($codevalue);
2017/08/29
2017/04/03
關於PHP, HTML and Javascript 程式碼的混肴與壓縮
把 php 程式碼的混肴密, 可以加上密碼
Free Online PHP Obfuscator
http://www.fopo.com.ar/
把 php 加密
jjencode demo
http://utf-8.jp/public/jjencode.html
美化你的 html code
Format, Beautify, Maxify, Unpack or Deobfuscate JavaScript/jQuery/HTML/JSON/CSS Codes
http://jenson.in/codeformatter/
壓縮你的 html code
Speed up your web pages
https://htmlcompressor.com
# 原始檔案內容
[mtchang@jangmt]$ cat phpobs.php
echo sha1('12345678');
?>
# 加密過後的內容-執行結果
[mtchang@jangmt]$ php phpobs_code.php
7c222fb2927d828af22f592134e8932480637c0d
# 沒有加密-執行結果
[mtchang@jangmt]$ php phpobs.php
7c222fb2927d828af22f592134e8932480637c0d
# 檔案大小差很多
[mtchang@jangmt]$ ls -la phpobs*
-rw-rw-r--. 1 mtchang mtchang 6634 Apr 3 01:17 phpobs_code.php
-rw-rw-r--. 1 mtchang mtchang 32 Apr 3 01:16 phpobs.php
Free Online PHP Obfuscator
http://www.fopo.com.ar/
把 php 加密
jjencode demo
http://utf-8.jp/public/jjencode.html
美化你的 html code
Format, Beautify, Maxify, Unpack or Deobfuscate JavaScript/jQuery/HTML/JSON/CSS Codes
http://jenson.in/codeformatter/
壓縮你的 html code
Speed up your web pages
https://htmlcompressor.com
![]() |
壓縮 html |
# 原始檔案內容
[mtchang@jangmt]$ cat phpobs.php
echo sha1('12345678');
?>
# 加密過後的內容-執行結果
[mtchang@jangmt]$ php phpobs_code.php
7c222fb2927d828af22f592134e8932480637c0d
# 沒有加密-執行結果
[mtchang@jangmt]$ php phpobs.php
7c222fb2927d828af22f592134e8932480637c0d
# 檔案大小差很多
[mtchang@jangmt]$ ls -la phpobs*
-rw-rw-r--. 1 mtchang mtchang 6634 Apr 3 01:17 phpobs_code.php
-rw-rw-r--. 1 mtchang mtchang 32 Apr 3 01:16 phpobs.php
![]() |
原始碼貼上去 |
![]() |
立即混淆看不懂程式碼 |
2017/02/04
PHP 檢查傳入的 DATE 日期是否合法,不合法的話就以現在的日期為值。
PHP 檢查傳入的日期時間是否合法,不合法的話就以現在的日期為值。
// get example: ?current_datepicker=2017-02-03
// ref: http://php.net/manual/en/function.checkdate.php
function validateDate($date, $format = 'Y-m-d H:i:s')
{
$d = DateTime::createFromFormat($format, $date);
return $d && $d->format($format) == $date;
}
// 取得 get 傳來的變數,如果有的話就是就是指定的 yy-mm-dd 沒有的話就是今天的日期
if(isset($_GET['current_datepicker'])) {
// 判斷格式資料是否正確
if(validateDate($_GET['current_datepicker'], 'Y-m-d')) {
$current_datepicker = $_GET['current_datepicker'];
}else{
$current_datepicker = date('Y-m-d');
}
}else{
// php 格式的 2017-02-24
$current_datepicker = date('Y-m-d');
}
// var_dump($current_datepicker);
// get example: ?current_datepicker=2017-02-03
// ref: http://php.net/manual/en/function.checkdate.php
function validateDate($date, $format = 'Y-m-d H:i:s')
{
$d = DateTime::createFromFormat($format, $date);
return $d && $d->format($format) == $date;
}
// 取得 get 傳來的變數,如果有的話就是就是指定的 yy-mm-dd 沒有的話就是今天的日期
if(isset($_GET['current_datepicker'])) {
// 判斷格式資料是否正確
if(validateDate($_GET['current_datepicker'], 'Y-m-d')) {
$current_datepicker = $_GET['current_datepicker'];
}else{
$current_datepicker = date('Y-m-d');
}
}else{
// php 格式的 2017-02-24
$current_datepicker = date('Y-m-d');
}
// var_dump($current_datepicker);
2016/10/09
PHP session_write_close()
PHP函式 php session_write_close()
End the current session and store session data.
session 的資料需要在 script 結束時才會儲存,所以當有2 個 script 同時執行時,後面的 script 會等前面的 script 執行完成再來跑,如果設定了 session_write_close() 就可以立即告訴程式,我後面的程序不會寫入 session 了,其他程式可以讀取 session 的內容來處理。
好處就是:程序不會被前一個 session 卡住,但是寫入 session 的行為就要很小心的處理。
範例:
http://konrness.com/php5/how-to-prevent-blocking-php-requests/
說明: http://php.net/manual/en/function.session-write-close.php
Session data is usually stored after your script terminated without the need to call session_write_close(), but as session data is locked to prevent concurrent writes only one script may operate on a session at any time. When using framesets together with sessions you will experience the frames loading one by one due to this locking. You can reduce the time needed to load all the frames by ending the session as soon as all changes to session variables are done.
ref:
http://xyz.cinc.biz/2012/01/php-session-lock.html
2016/10/06
RabbitMQ 實作 AMQP 的開放原始碼訊息代理軟體
RabbitMQ 是一個訊息中介軟體 (broker) 可以接受並轉發訊息,他是 AMQP 的實作。
功能類似郵局機制,類似 unix Email system。
主要處理的存儲、轉發 binary blobs of data (二進制資料)
那 AMQP 它和傳統的 SMTP 差異在哪裡?? 重點在可以非同步,並且可靠。
![]() |
ref: http://blogs.mulesoft.com/dev/news-dev/amqp-and-the-future-of-web-messaging/ |
系統中的角色:
訊息發布者 publisher = 訊息消費者 consumer
訊息代理 brokers
訊息生產者 producers
訊息交換模型 (ref: http://rabbitmq.mr-ping.com/AMQP/AMQP_0-9-1_Model_Explained.html )
使用 RabbitMQ 的顧客 https://blog.pivotal.io/channels/data-science-pivotal
Pivotal Labs 原來不只玩 big data 它是一間很有趣的公司呀!!(MADlib 是它開發中的產品..)
因為還不是很熟悉,所以放了很多參考連結:
官方網站 http://www.rabbitmq.com in github https://github.com/rabbitmq
官方教學 http://www.rabbitmq.com/getstarted.html
中文教學 http://rabbitmq.mr-ping.com/
WIKI 介紹 https://zh.wikipedia.org/wiki/RabbitMQ
PHP 函式 http://php.net/manual/fa/book.amqp.php
PHP amqplib in GITHUB https://github.com/php-amqplib/php-amqplib
Python 函式 https://barryp.org/software/py-amqplib/
使用經驗心得 http://pjack1981.blogspot.tw/2012/08/rabbitmq.html
介紹 http://lab.howie.tw/2012/07/whats-different-between-amqp-and-jms.html
AMQP future of web messageing http://blogs.mulesoft.com/dev/news-dev/amqp-and-the-future-of-web-messaging/
2016/06/26
Redis-Server with PHP 的使用 in CentOS7
Redis-Server with PHP 的使用 in CentOS7
* Redis DB server 的用途
Redis 是一個 key-value 架構的 database , 且因為它工作在記憶體上面,所以速度非常的快。
可以用來當 DB cache 加速的功能或是需要快速反應的 DB
* CentOS 7 的 Redis-server 安裝方式
# yum install redis -y
* 安裝參考
http://sharadchhetri.com/2014/10/04/install-redis-server-centos-7-rhel-7/
* 通常會搭配 php 等 client 端工具一起安裝, 這裡我是以 php56w 的版本安裝, 因為有比較多 lib 支援
# yum install php56w-pecl-redis
* php56w 可以參考 webtatic 釋出的 yum repo 安裝參考 https://webtatic.com/packages/php56/ RHEL7 OR EPEL7 官方網站跑的版本有點慢,可以先參考這個版本。
* 啟動
# systemctl start redis.service
* 預設開機啟動
# systemctl enable redis.service
* 看狀態
# systemctl status redis.service
* 測試 , 剛裝好的 redis-server 是沒有密碼的, 且只能 127.0.0.1 執行。 可以用 redis-cli client 端工具測試 PONG 是正確的回應。
[root@c7 ~]# redis-cli ping
PONG
* 所以我都會設定個密碼, 並且把 bind 打開讓所有人都可以連上來。
* 請找到下面兩行, 修改為你要的密碼及主機 ip
# vim /etc/redis.conf
bind 111.111.22.22
requirepass 123456
* 重新啟動
# systemctl restart redis.service
* 驗證看看 port , 應該是 6379
# netstat -antlp | grep redis
tcp 0 0 111.111.22.22:6379 0.0.0.0:* LISTEN 22326/redis-server
* 加了密碼的測試
# redis-cli -a '123456' -h 111.111.22.22 ping
PONG
* man page 內的 Examples , 不帶密碼的測試, 可以試試看
cat /etc/passwd | redis-cli -x set mypasswd
redis-cli get mypasswd
redis-cli -r 100 lpush mylist x
redis-cli -r 100 -i 1 info | grep used_memory_human:
redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3
redis-cli --scan --pattern '*:12345*'
* 專案網站 http://redis.io/
* 文件網站:http://redis.io/documentation
* 中文翻譯的教學文件(redis-cli) http://www.runoob.com/redis/redis-tutorial.html
* Redis 中文文件 https://www.gitbook.com/book/wizardforcel/redis-doc/details
* 通常會裝個 REDIS 桌面管理工具來觀看, 否則看不到東西怪怪的 http://redisdesktop.com/download

----------------------------------------
* PHP 在 REDIS 上面的操作
----------------------------------------
* 在 php 上面有個 phpredis/phpredis 的函式庫, 可以讓你利用他來寫 redis 上面的程式
* https://github.com/phpredis/phpredis github 上面的 readme 就是使用的方式, 幾乎可以很完整的操作了
使用 php + redis server 模擬 session 的動作
https://github.com/mtchang/code/blob/master/redis_session.php
* 可以使用 phpRedisAdmin 工具, 從網頁觀看 redis 的使用狀況
https://github.com/erikdubbelboer/phpRedisAdmin 原始碼位置,此工具可以用 composer 安裝。
* 可以 把 PHP 的 session handler 改用 redis server 紀錄
方法如這裡 https://github.com/phpredis/phpredis#php-session-handler
* 直接修改 php.ini 檔案,找到 session 這段, 設定完成後 restart httpd or php-fpm 就可以
# vim /etc/php.ini
[Session]
; 支持 redis db 的 php session
session.save_handler = redis
session.save_path = "tcp://111.111.22.22:6379?auth=123456"
* 也可以寫成類似這樣, 當多台主機同時用時可以分散負載.
;session.save_path="tcp://127.0.0.1:11211?persistent=1&weight=1&timeout=1&retry_interval=15″
* 在 centos7 實際執行時發現, 因為 php.ini 有很多地方都有放, 要注意不同的設定檔蓋掉這個設定。
# 當網頁可以執行 phpinfo(); 會有有安全性風險 , 有可能洩漏你的認證密碼, 建議多設定防火牆防外賊。
[root@c7 etc]# php -i | grep session
.... skip ....
session.save_path => tcp://111.111.22.22:6379?auth=123456 => tcp://111.111.22.22:6379?auth=123456
.... skip ....
* 建議設定 iptalbes 範例
# 擋掉特定 ip , 允許特定 ip, 開啟 port
EXTIF="enp2s0f0" # 系統對外網卡
iptables -A INPUT -p TCP -s 111.111.69.0/24 --dport 6379 --sport 1024:65534 -j ACCEPT # redis accept
iptables -A INPUT -p TCP -i $EXIT --dport 6379 --sport 1024:65534 -j REJECT # redis reject
# 效能測試
# redis-benchmark -a '123456' -h 111.111.22.22 -c 1000 -n 100 -q
PING_INLINE: 3703.70 requests per second
PING_BULK: 7692.31 requests per second
SET: 4347.83 requests per second
GET: 8333.33 requests per second
INCR: 11111.11 requests per second
LPUSH: 8333.33 requests per second
LPOP: 3703.70 requests per second
SADD: 9090.91 requests per second
SPOP: 8333.33 requests per second
LPUSH (needed to benchmark LRANGE): 4347.83 requests per second
LRANGE_100 (first 100 elements): 3448.28 requests per second
LRANGE_300 (first 300 elements): 9090.91 requests per second
LRANGE_500 (first 450 elements): 8333.33 requests per second
LRANGE_600 (first 600 elements): 7142.86 requests per second
MSET (10 keys): 8333.33 requests per second
* 使用 redis 來當成 php session handler in Ubuntu
https://www.digitalocean.com/community/tutorials/how-to-set-up-a-redis-server-as-a-session-handler-for-php-on-ubuntu-14-04
* 可以用來做統計的
piwik http://demo.piwik.org/
* redis 統計工具
https://github.com/junegunn/redis-stat
* 程式開發參考
http://www.cnblogs.com/ikodota/archive/2012/03/05/php_redis_cn.html
https://github.com/phpredis/phpredis
https://scotch.io/tutorials/getting-started-with-redis-in-php
http://www.runoob.com/redis/redis-hashes.html
* Redis DB server 的用途
Redis 是一個 key-value 架構的 database , 且因為它工作在記憶體上面,所以速度非常的快。
可以用來當 DB cache 加速的功能或是需要快速反應的 DB
* CentOS 7 的 Redis-server 安裝方式
# yum install redis -y
* 安裝參考
http://sharadchhetri.com/2014/10/04/install-redis-server-centos-7-rhel-7/
* 通常會搭配 php 等 client 端工具一起安裝, 這裡我是以 php56w 的版本安裝, 因為有比較多 lib 支援
# yum install php56w-pecl-redis
* php56w 可以參考 webtatic 釋出的 yum repo 安裝參考 https://webtatic.com/packages/php56/ RHEL7 OR EPEL7 官方網站跑的版本有點慢,可以先參考這個版本。
* 啟動
# systemctl start redis.service
* 預設開機啟動
# systemctl enable redis.service
* 看狀態
# systemctl status redis.service
* 測試 , 剛裝好的 redis-server 是沒有密碼的, 且只能 127.0.0.1 執行。 可以用 redis-cli client 端工具測試 PONG 是正確的回應。
[root@c7 ~]# redis-cli ping
PONG
* 所以我都會設定個密碼, 並且把 bind 打開讓所有人都可以連上來。
* 請找到下面兩行, 修改為你要的密碼及主機 ip
# vim /etc/redis.conf
bind 111.111.22.22
requirepass 123456
* 重新啟動
# systemctl restart redis.service
* 驗證看看 port , 應該是 6379
# netstat -antlp | grep redis
tcp 0 0 111.111.22.22:6379 0.0.0.0:* LISTEN 22326/redis-server
* 加了密碼的測試
# redis-cli -a '123456' -h 111.111.22.22 ping
PONG
* man page 內的 Examples , 不帶密碼的測試, 可以試試看
cat /etc/passwd | redis-cli -x set mypasswd
redis-cli get mypasswd
redis-cli -r 100 lpush mylist x
redis-cli -r 100 -i 1 info | grep used_memory_human:
redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3
redis-cli --scan --pattern '*:12345*'
* 專案網站 http://redis.io/
* 文件網站:http://redis.io/documentation
* 中文翻譯的教學文件(redis-cli) http://www.runoob.com/redis/redis-tutorial.html
* Redis 中文文件 https://www.gitbook.com/book/wizardforcel/redis-doc/details
* 通常會裝個 REDIS 桌面管理工具來觀看, 否則看不到東西怪怪的 http://redisdesktop.com/download

----------------------------------------
* PHP 在 REDIS 上面的操作
----------------------------------------
* 在 php 上面有個 phpredis/phpredis 的函式庫, 可以讓你利用他來寫 redis 上面的程式
* https://github.com/phpredis/phpredis github 上面的 readme 就是使用的方式, 幾乎可以很完整的操作了
使用 php + redis server 模擬 session 的動作
https://github.com/mtchang/code/blob/master/redis_session.php
* 可以使用 phpRedisAdmin 工具, 從網頁觀看 redis 的使用狀況
https://github.com/erikdubbelboer/phpRedisAdmin 原始碼位置,此工具可以用 composer 安裝。
![]() |
PHPRedisAdmin 網頁界面看 redis session 程式 |
* 可以 把 PHP 的 session handler 改用 redis server 紀錄
方法如這裡 https://github.com/phpredis/phpredis#php-session-handler
* 直接修改 php.ini 檔案,找到 session 這段, 設定完成後 restart httpd or php-fpm 就可以
# vim /etc/php.ini
[Session]
; 支持 redis db 的 php session
session.save_handler = redis
session.save_path = "tcp://111.111.22.22:6379?auth=123456"
* 也可以寫成類似這樣, 當多台主機同時用時可以分散負載.
;session.save_path="tcp://127.0.0.1:11211?persistent=1&weight=1&timeout=1&retry_interval=15″
* 在 centos7 實際執行時發現, 因為 php.ini 有很多地方都有放, 要注意不同的設定檔蓋掉這個設定。
![]() |
PHPSESSION 再 redis 上的顯示 |
# 當網頁可以執行 phpinfo(); 會有有安全性風險 , 有可能洩漏你的認證密碼, 建議多設定防火牆防外賊。
[root@c7 etc]# php -i | grep session
.... skip ....
session.save_path => tcp://111.111.22.22:6379?auth=123456 => tcp://111.111.22.22:6379?auth=123456
.... skip ....
* 建議設定 iptalbes 範例
# 擋掉特定 ip , 允許特定 ip, 開啟 port
EXTIF="enp2s0f0" # 系統對外網卡
iptables -A INPUT -p TCP -s 111.111.69.0/24 --dport 6379 --sport 1024:65534 -j ACCEPT # redis accept
iptables -A INPUT -p TCP -i $EXIT --dport 6379 --sport 1024:65534 -j REJECT # redis reject
# 效能測試
# redis-benchmark -a '123456' -h 111.111.22.22 -c 1000 -n 100 -q
PING_INLINE: 3703.70 requests per second
PING_BULK: 7692.31 requests per second
SET: 4347.83 requests per second
GET: 8333.33 requests per second
INCR: 11111.11 requests per second
LPUSH: 8333.33 requests per second
LPOP: 3703.70 requests per second
SADD: 9090.91 requests per second
SPOP: 8333.33 requests per second
LPUSH (needed to benchmark LRANGE): 4347.83 requests per second
LRANGE_100 (first 100 elements): 3448.28 requests per second
LRANGE_300 (first 300 elements): 9090.91 requests per second
LRANGE_500 (first 450 elements): 8333.33 requests per second
LRANGE_600 (first 600 elements): 7142.86 requests per second
MSET (10 keys): 8333.33 requests per second
* 使用 redis 來當成 php session handler in Ubuntu
https://www.digitalocean.com/community/tutorials/how-to-set-up-a-redis-server-as-a-session-handler-for-php-on-ubuntu-14-04
* 可以用來做統計的
piwik http://demo.piwik.org/
* redis 統計工具
https://github.com/junegunn/redis-stat
* 程式開發參考
http://www.cnblogs.com/ikodota/archive/2012/03/05/php_redis_cn.html
https://github.com/phpredis/phpredis
https://scotch.io/tutorials/getting-started-with-redis-in-php
http://www.runoob.com/redis/redis-hashes.html
2016/03/29
將 CSV 檔案加上 UTF BOM 讓它可以在 Windows 被 EXCEL 正確的開啟沒有亂碼的問題
將 CSV 檔案加上 UTF BOM 讓它可以在 Windows 被 EXCEL 正確的開啟沒有亂碼的問題
在 UTF-8 文件中放置 BOM 主要是微軟系統的習慣。但是真的沒有必要帶拉!!!!
http://stackoverflow.com/questions/2223882/whats-different-between-utf-8-and-utf-8-without-bom
According to the Unicode standard, the BOM for UTF-8 files is not recommended:
![]() |
圖片和內文不太相關 |
下面提供一種在 windows 上面,政治正確的解法。 XDXD
// ========================================================
// 產生現在的秒數
$time_string = date("YmdHis");
// 寫入 utf8 with BOM
function writeUTF8File($filename,$content)
{
$f = fopen($filename, 'w');
fwrite($f, pack("CCC", 0xef,0xbb,0xbf));
fwrite($f,$content);
fclose($f);
}
$f = 'uploads/private/'.$time_string.'.csv';
$fdir = 'uploads/private/';
// 檔案不存在就先建立檔案
if (!file_exists($fdir)) {
mkdir($fdir);
}
writeUTF8File($f,$csv);
echo 'CSV 輸出完成,請點選連結下載。
';
// ========================================================
2016/03/28
取得 mysql 資料表中的「欄位名稱」以及「欄位註解」
取得 mysql 資料表中的「欄位名稱」以及「欄位註解」
在 MySQL 資料庫中,宣告資料表的過程,可以一併把欄位名稱寫在 COMMENT 選項中,如果在程式可以把這個 COMMENT 也抓出來配合欄位的名稱,可以產生自動把整個表 DUMP 出來成為一個 CSV 不就很方便。
// -----------------------------------------------
$table='表格名稱';
// 資料庫中表的欄位抬頭資訊
$col_sql = "SELECT COLUMN_NAME,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = '$table';";
$col = runSQL($col_sql);
// var_dump($col);
// 資料欄位
$sql = "SELECT * FROM `$table` WHERE 1;";
$row = runSQL($sql);
// var_dump($row);
$csv = '';
// 欄位名註解
//echo "
";
for($i=1;$i<$col[0];$i++){
//echo $col[$i]->COLUMN_COMMENT.", ";
$csv = $csv.$col[$i]->COLUMN_COMMENT.", ";
}
$csv = $csv."\n";
// 欄位名稱
//echo "
";
for($i=1;$i<$col[0];$i++){
//echo $col[$i]->COLUMN_NAME.", ";
$csv = $csv.$col[$i]->COLUMN_NAME.", ";
}
$csv = $csv."\n";
// 資料列取得欄位
//echo "
";
for($j=1;$j<$row[0];$j++){
for($i=1;$i<$col[0];$i++){
$k = $col[$i]->COLUMN_NAME;
//echo $row[$j]->$k.', ';
$csv = $csv.$row[$j]->$k.', ';
}
$csv = $csv."\n";
//echo "
";
}
//echo "
";
//echo " 共有 $i 欄 $j 列
";
$csv = $csv."\n 共有 $i 欄 $j 列 \n";
echo nl2br($csv);
// -----------------------------------------------
* 同時放在 github https://github.com/mtchang/ITCNotes/blob/master/mysql_get_tableinfo2csv
* runSQL() 函式請參考這一篇 http://blog.jangmt.com/2016/03/mysql-php-mysql-pdo.html
在 MySQL 資料庫中,宣告資料表的過程,可以一併把欄位名稱寫在 COMMENT 選項中,如果在程式可以把這個 COMMENT 也抓出來配合欄位的名稱,可以產生自動把整個表 DUMP 出來成為一個 CSV 不就很方便。
![]() |
圖片和內文不太相關 |
// -----------------------------------------------
$table='表格名稱';
// 資料庫中表的欄位抬頭資訊
$col_sql = "SELECT COLUMN_NAME,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = '$table';";
$col = runSQL($col_sql);
// var_dump($col);
// 資料欄位
$sql = "SELECT * FROM `$table` WHERE 1;";
$row = runSQL($sql);
// var_dump($row);
$csv = '';
// 欄位名註解
//echo "
";
for($i=1;$i<$col[0];$i++){
//echo $col[$i]->COLUMN_COMMENT.", ";
$csv = $csv.$col[$i]->COLUMN_COMMENT.", ";
}
$csv = $csv."\n";
// 欄位名稱
//echo "
";
for($i=1;$i<$col[0];$i++){
//echo $col[$i]->COLUMN_NAME.", ";
$csv = $csv.$col[$i]->COLUMN_NAME.", ";
}
$csv = $csv."\n";
// 資料列取得欄位
//echo "
";
for($j=1;$j<$row[0];$j++){
for($i=1;$i<$col[0];$i++){
$k = $col[$i]->COLUMN_NAME;
//echo $row[$j]->$k.', ';
$csv = $csv.$row[$j]->$k.', ';
}
$csv = $csv."\n";
//echo "
";
}
//echo "
";
//echo " 共有 $i 欄 $j 列
";
$csv = $csv."\n 共有 $i 欄 $j 列 \n";
echo nl2br($csv);
// -----------------------------------------------
* 同時放在 github https://github.com/mtchang/ITCNotes/blob/master/mysql_get_tableinfo2csv
* runSQL() 函式請參考這一篇 http://blog.jangmt.com/2016/03/mysql-php-mysql-pdo.html
2016/03/27
mysql 中文亂碼的避免及 php mysql pdo 宣告取用方式
Mariadb 和 Mysql 都會有亂碼, 只要它預設編碼還是在 latin 的時還是一直會發生.
所以改成 utf8 編碼是一個對於東亞語系的文字,會比較方便。
UTF8 的介紹請看 wiki https://zh.wikipedia.org/wiki/UTF-8
xxx_bin (區分大小寫)
xxx_general_ci (不區分大小寫)
Collation 每個字符集的排序規則
http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html
在 mysql 資料庫中有兩個編碼系統 UCS2 及 UTF8
utf8 使用 1~3 bytes ,帶有 65536 個組合的編碼
utf32 與 utf8mb4 是完整的的 unicode ,差異在 utf32 固定 4 bytes ,而 utf8mb4 則是彈性使用 1~4 bytes 。
utf8mb4 從 MySQL 5.5.3 (released March 2010). 開始提供
目前預設的編碼系統為
xxx_general_ci (default)
為了中文語系使用不要出問題,建議修正如下:
-----------------------------------------------------
# 修正 mysql 的設定檔
[root@c7 my.cnf.d]# more /etc/my.cnf.d/my-huge.cnf
[client]
default-character-set=utf8mb4
[code]
default-character-set=utf8mb4
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
# restart mysql service
# 檢查系統的編碼變數
----------------------------
[root@c7 my.cnf.d]# mysql -u root -p
Enter password:
MariaDB [(none)]> SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name | Value |
+--------------------------+--------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| collation_connection | utf8mb4_general_ci |
| collation_database | utf8mb4_general_ci |
| collation_server | utf8mb4_general_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)
character_set_filesystem 要維持 binary
character_set_system 是唯讀變數
# 配合 PHP 程式上我會宣告如下,寫用一個 function 來取用 mysql 。
// -----------------------------------------------------------------------------------------
// 請在根目錄下建立一個檔案 VERSION.txt 檔案內容放置 release or developer , 依據此變數自動判斷目前所在開發環境
$system_mode = file_get_contents("VERSION.txt");
//$system_mode = 'release';
//$system_mode = 'developer';
if($system_mode == 'developer') {
// sql DB infomation -- for developer
$dbhost ='localhost';
$dbname ='exampleDB';
$dbuser ='exampleUSER';
$dbpassword ='example';
}elseif($system_mode == 'release') {
// sql DB infomation -- for release
$dbhost ='localhost';
$dbname ='exampleDB';
$dbuser ='exampleUSER';
$dbpassword ='example';
}else{
// 沒有設定 STOP
die('System mode set error !!!');
}
// ----------------------------------------------------------------------
//
// 連接資料庫的的設定,預設將 set name utf8 開啟
//
try {
// 在 PDO 宣告的時候就要將編碼一併宣告。 ref.pdo-mysql.connection
global $dbh;
$dsn = "mysql:host=$dbhost;dbname=$dbname";
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4');
$dbh = new PDO($dsn, $dbuser, $dbpassword, $options);
} catch (PDOException $e) {
print "DB connect Error!: " . $e->getMessage() . "
";
die();
}
// ---------------------------------------------------------------------
// run SQL command then return $result
// $result[0] --> 資料數量, 如果為 0 表示沒有變動的列
// $result[1] ~ $result[n] --> 資料內容,從第一筆開始
// 使用方式 example:
// $result = runSQL($sql);
// var_dump($result);
// ---------------------------------------------------------------------
function runSQL($query)
{
global $dbh;
try {
$stmt = $dbh->prepare("$query");
$stmt->execute();
// 查詢到的數量, 放到此變數的 [0] 索引位置
$db_dump_result_all[0] = $stmt->rowCount();
$i=1;
// 以物件方式存變數物件取用以 $result->var 方式取用
while ($db_dump_result = $stmt->fetch(PDO::FETCH_OBJ)) {
$db_dump_result_all[$i] = $db_dump_result;
$i++;
}
} catch (PDOException $e) {
return("DB connect Error!: $e->getMessage() , SQL: $query ");
die();
}
return($db_dump_result_all);
}
// --------------------------------------------------------------------
以上放在 github 上https://github.com/mtchang/ITCNotes/blob/master/mysql_utf8mb4_pdo.txt
更多閱讀:
How to support full Unicode in MySQL databases https://mathiasbynens.be/notes/mysql-utf8mb4
utf8mb4 編碼使用的一些紀錄 https://twpug.net/discussion/8646/utf8mb4-%E7%B7%A8%E7%A2%BC%E4%BD%BF%E7%94%A8%E7%9A%84%E4%B8%80%E4%BA%9B%E7%B4%80%E9%8C%84
stackoverflow about utf8mb4 http://stackoverflow.com/tags/utf8mb4/info
維基百科 utf8 http://zh.wikipedia.org/wiki/UTF-8
解釋 mysql 的 Unicode Character Sets http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html
所以改成 utf8 編碼是一個對於東亞語系的文字,會比較方便。
UTF8 的介紹請看 wiki https://zh.wikipedia.org/wiki/UTF-8
xxx_bin (區分大小寫)
xxx_general_ci (不區分大小寫)
Collation 每個字符集的排序規則
http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html
在 mysql 資料庫中有兩個編碼系統 UCS2 及 UTF8
utf8 使用 1~3 bytes ,帶有 65536 個組合的編碼
utf32 與 utf8mb4 是完整的的 unicode ,差異在 utf32 固定 4 bytes ,而 utf8mb4 則是彈性使用 1~4 bytes 。
utf8mb4 從 MySQL 5.5.3 (released March 2010). 開始提供
目前預設的編碼系統為
xxx_general_ci (default)
為了中文語系使用不要出問題,建議修正如下:
-----------------------------------------------------
# 修正 mysql 的設定檔
[root@c7 my.cnf.d]# more /etc/my.cnf.d/my-huge.cnf
[client]
default-character-set=utf8mb4
[code]
default-character-set=utf8mb4
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
# restart mysql service
# 檢查系統的編碼變數
----------------------------
[root@c7 my.cnf.d]# mysql -u root -p
Enter password:
MariaDB [(none)]> SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name | Value |
+--------------------------+--------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| collation_connection | utf8mb4_general_ci |
| collation_database | utf8mb4_general_ci |
| collation_server | utf8mb4_general_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)
character_set_filesystem 要維持 binary
character_set_system 是唯讀變數
# 配合 PHP 程式上我會宣告如下,寫用一個 function 來取用 mysql 。
// -----------------------------------------------------------------------------------------
// 請在根目錄下建立一個檔案 VERSION.txt 檔案內容放置 release or developer , 依據此變數自動判斷目前所在開發環境
$system_mode = file_get_contents("VERSION.txt");
//$system_mode = 'release';
//$system_mode = 'developer';
if($system_mode == 'developer') {
// sql DB infomation -- for developer
$dbhost ='localhost';
$dbname ='exampleDB';
$dbuser ='exampleUSER';
$dbpassword ='example';
}elseif($system_mode == 'release') {
// sql DB infomation -- for release
$dbhost ='localhost';
$dbname ='exampleDB';
$dbuser ='exampleUSER';
$dbpassword ='example';
}else{
// 沒有設定 STOP
die('System mode set error !!!');
}
// ----------------------------------------------------------------------
//
// 連接資料庫的的設定,預設將 set name utf8 開啟
//
try {
// 在 PDO 宣告的時候就要將編碼一併宣告。 ref.pdo-mysql.connection
global $dbh;
$dsn = "mysql:host=$dbhost;dbname=$dbname";
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4');
$dbh = new PDO($dsn, $dbuser, $dbpassword, $options);
} catch (PDOException $e) {
print "DB connect Error!: " . $e->getMessage() . "
";
die();
}
// ---------------------------------------------------------------------
// run SQL command then return $result
// $result[0] --> 資料數量, 如果為 0 表示沒有變動的列
// $result[1] ~ $result[n] --> 資料內容,從第一筆開始
// 使用方式 example:
// $result = runSQL($sql);
// var_dump($result);
// ---------------------------------------------------------------------
function runSQL($query)
{
global $dbh;
try {
$stmt = $dbh->prepare("$query");
$stmt->execute();
// 查詢到的數量, 放到此變數的 [0] 索引位置
$db_dump_result_all[0] = $stmt->rowCount();
$i=1;
// 以物件方式存變數物件取用以 $result->var 方式取用
while ($db_dump_result = $stmt->fetch(PDO::FETCH_OBJ)) {
$db_dump_result_all[$i] = $db_dump_result;
$i++;
}
} catch (PDOException $e) {
return("DB connect Error!: $e->getMessage() , SQL: $query ");
die();
}
return($db_dump_result_all);
}
// --------------------------------------------------------------------
以上放在 github 上https://github.com/mtchang/ITCNotes/blob/master/mysql_utf8mb4_pdo.txt
更多閱讀:
How to support full Unicode in MySQL databases https://mathiasbynens.be/notes/mysql-utf8mb4
utf8mb4 編碼使用的一些紀錄 https://twpug.net/discussion/8646/utf8mb4-%E7%B7%A8%E7%A2%BC%E4%BD%BF%E7%94%A8%E7%9A%84%E4%B8%80%E4%BA%9B%E7%B4%80%E9%8C%84
stackoverflow about utf8mb4 http://stackoverflow.com/tags/utf8mb4/info
維基百科 utf8 http://zh.wikipedia.org/wiki/UTF-8
解釋 mysql 的 Unicode Character Sets http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html
2015/12/09
php7 vs. GO lang vs. C on CentOS 7 Linux 速度比較
php7 vs. GO lang vs. C on CentOS 7 Linux 速度比較
繼上一篇後,想說 php7 已經很快了,但是到底和原生 C 差多少.....
所以就抓了php7 , GO 及 C 三種語言來比較看看氣泡演算法, 12 各項目排序 90萬次花費的時間。
結論:
PHP7 ==> 5.9242088794708 s
GO ==> 0.228.885223 s
C ==> 0.174889 s
換算一下, ms, us 的單位,結論是 php7 連 GO 和 C 的車尾燈都看不到...
GO 還可以看得到C 的車尾燈!!!!!且 GO 比 C 好寫多了,我可以接受這一點點的微小差距。
有圖有真相....
C bubble sort 演算法 http://www.programmingsimplified.com/c/source-code/c-program-bubble-sort
C 計算時間差 http://www.binarytides.com/get-time-difference-in-microtime-in-c/
php 及 go 的程式碼 https://jaxbot.me/articles/benchmarks_nodejs_vs_go_vs_php_3_14_2013
別人做的 php vs go https://www.ransona.com/blog/2014/11/06/go-vs-php-performance-restful-service/
2015/12/08
升級 php7 可以不用急著換電腦.....!!!! on CentOS 7
升級 php7 可以不用急著換電腦.....!!!! on CentOS 7 Linux
先講結論:
升級前 2.767 sec
升級後 0.88 sec
----------------------
速度增加了 3.14 倍 ,這台是 Intel Core I5 CPU, RAM 4GB 的個人PC。


更新可以參考這篇文章, CentOS 6 OR CentOS 7 都可以更新。
https://webtatic.com/packages/php70/
但是要注意,如果你的 Linux 系統已經有安裝第三方套件,或手動安裝的請小心更新後會毀掉。我的是都用官方的套件及 EPEL更新,直接上去沒有發生大的問題資料也都存在。
另外如果你有自行開發的程式,也需要注意套件的相容性,再行安裝。
測試程式,我是抓 http://www.php-benchmark-script.com/ 這個測試程式。
程式沒有針對平行化、I/O 這些評估,但已經明顯看得出差異。
2015/02/17
PHP Multi Process 程式以 PING 多主機應用為範例
嘗試使用 php pcntl_fork 寫各 ping 程式,一次偵測多台主機。
但目前還有些問題,如子程序沒辦法再程式中傳回父程序,這部份還要再仔細看一下手冊看看該如何處理。
https://github.com/mtchang/ping/blob/master/ping.php
ref:
http://php.net/manual/en/function.pcntl-fork.php
http://pkwbim-programming-note.blogspot.tw/2008/01/phpmulti-process-1.html
http://www.systn.com/data/articles/207_tw.html
但目前還有些問題,如子程序沒辦法再程式中傳回父程序,這部份還要再仔細看一下手冊看看該如何處理。
https://github.com/mtchang/ping/blob/master/ping.php
ref:
http://php.net/manual/en/function.pcntl-fork.php
http://pkwbim-programming-note.blogspot.tw/2008/01/phpmulti-process-1.html
http://www.systn.com/data/articles/207_tw.html
2014/07/27
WAMPServer 2.5 php_pgsql.dll 有問題?無法正常的工作。
WAMPServer 2.5 php_pgsql.dll 有問題?無法正常的工作。
因為想要讓開發的工作更有效率,於是在自己的電腦上安裝 WAMP 當成本地端的開發工具
WAMP 預設的 DEBUG 工具很齊全,對於除錯真的很方便。
但今天改開發 PHP + PostgreSQL 的程式,發現明明 PHP_PDO_PGSQL 都有啟動,但是 phpinfo()
怎樣都看不到相關的模組訊息。(應該要有 pdo_pgsql and pdo_pgsql 這兩個模組才是)
查了半天,發現在 PHP for windows 5.25 "php_pgsql.dll" 還可以工作,升級 PHP 到 5.5.12 就不正常了....
快速的修正方式:
(1) 安裝 Postgresql for windows 版,在本地端機器上面。
http://www.enterprisedb.com/products-services-training/pgdownload#windows
裝好後,看看在地下的路徑是否有這個檔案 libpq.dll
(2) 將該檔案讓 apache 掛載
打開 windows apache httpd.conf 設定檔,找個好地方把底下這一行放到設定檔案內,然後重新啟動 APACHE
(3) 去看看你的 http://localhost/?phpinfo 應該就有 pdo_pgsql and pdo_pgsql 這兩個模組了。
參考:
http://stackoverflow.com/questions/551734/php-not-loading-php-pgsql-dll-on-windows
因為想要讓開發的工作更有效率,於是在自己的電腦上安裝 WAMP 當成本地端的開發工具
WAMP 預設的 DEBUG 工具很齊全,對於除錯真的很方便。
但今天改開發 PHP + PostgreSQL 的程式,發現明明 PHP_PDO_PGSQL 都有啟動,但是 phpinfo()
怎樣都看不到相關的模組訊息。(應該要有 pdo_pgsql and pdo_pgsql 這兩個模組才是)
查了半天,發現在 PHP for windows 5.25 "php_pgsql.dll" 還可以工作,升級 PHP 到 5.5.12 就不正常了....
快速的修正方式:
(1) 安裝 Postgresql for windows 版,在本地端機器上面。
http://www.enterprisedb.com/products-services-training/pgdownload#windows
裝好後,看看在地下的路徑是否有這個檔案 libpq.dll
(2) 將該檔案讓 apache 掛載
打開 windows apache httpd.conf 設定檔,找個好地方把底下這一行放到設定檔案內,然後重新啟動 APACHE
LoadFile "C:/Program Files/PostgreSQL/9.3/bin/libpq.dll"
(3) 去看看你的 http://localhost/?phpinfo 應該就有 pdo_pgsql and pdo_pgsql 這兩個模組了。
![]() |
pdo_pgsql and pdo_pgsql 這兩個模組 |
參考:
http://stackoverflow.com/questions/551734/php-not-loading-php-pgsql-dll-on-windows
2013/09/07
AppServ 懶人包的資安問題與檢測(請不要再使用 APPSERV 懶人包)
此文同時刊載於 http://www.openfoundry.org/tw/foss-programs/9073-appserv-
----
APPSERV (http://www.appservnetwork.com/)是一個 Windows 下很成功的懶人包專案,它把 Apache 、PHP、MySQL以及 PHPMyAdmin 整合打包成為一個安裝檔案,對於入門的程式開發人員很方便。也因為它在 2006 年就推出所以到現在仍是下載率很高的專案,每個月約有 10 萬次下載。
但是問題就在這裡,它目前的版本為 2008-06-10 的版本(http://sourceforge.net/projects/appserv/files/?source=navbar),作者已經有 5 年多沒有更新了,但是還是有那麼多人下載使用。
在 2009 、2010 有很多 phpMyAdmin 的漏洞陸續被公開,以 CVE-2009-1151(http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-1151) 為例,它說明在 phpMyAdmin 的 setup.php 程式中有個程式碼可以寫入檔案的漏洞存在。如果找一下還會發現已經有人將它寫成自動化入侵的工具程式。
如果知道漏洞存在並補強其實不會造成什麼問題,但問題在於使用 APPSERV 的大多為初學者或對於系統程式不熟悉的使用者,只求網站能工作不會注意這些細節的問題。如果你用 google 的 inurl + site + intext 搭配搜尋你會發現真的很多人不在意,且甚至把這個網站它放到公開的網路上工作。關鍵字:「phpmyadmin scripts setup.php win32」
在 2013/05 月的時候 TACERT 已經針對這部份的入侵細節做了一份攻擊行為的分析報告(http://cert.tanet.edu.tw/pdf/phpmyadmin.pdf),攻擊者針對這部份的目的性是對於安裝 APPSERV 的主機植入 IRC BOT 並控制該主機成為殭屍網路(http://zh.wikipedia.org/wiki/%E6%AE%AD%E5%B1%8D%E7%B6%B2%E7%B5%A1 )的一部分。
如果稍微有些概念的話你會發現,每月APPSERV 懶人包 10 萬的下載量轉換為殭屍網路主機如果有 1% 轉換成功的話那就是 1000 台主機,所以只要透過 APPSERV 的漏洞幾個月內就可入侵控制數萬台以上的主機,屆時如需要發動網路攻擊也就非常的容易。底下紀錄是我手上隨便一台機器的 apache 紀錄檔,隨便找一下網路上四處都有機器人在掃描這個漏洞。
所以你也可以寫個程式掃描你所在的網路,看是否有人在使用 APPSERV 。底下是我寫的小工具檢測 phpmyadmin/scrips 網址是否存在、setup.php 是否存在以及是否為 Win32 主機,用來檢測我的網路有沒有這種「肥羊」主機的存在。程式碼我放在 GITHUB (https://github.com/mtchang/test/blob/master/test_appserv.sh) 內,使用說明在這裡(https://github.com/mtchang/test/blob/master/test_appserv.README)。
所以這裡要請大家幫忙的是不要在教學、研究及正式網站上使用 APPSERV 了,目前國內的資管、資工科系在網站教學課程上面很多是使用 APPSERV 當作教學練習的工具,且根據我的經驗發現很多大學生、研究生是用 APPSERV 架設網站收集研究資料,顯示該套件已經被很多人接受不易改變。
對於初學者 APPSERV 的替代方案建議可使用 WampServer (http://www.wampserver.com) 或是 XAMPP (http://www.apachefriends.org/zh_tw/xampp-windows.html) ,這些活躍的懶人包套件專案,如果網站是放到公開網路上更是需要注意安全性的細節。
當然,最好的方法是請官方網站的維護者更新修正,我想它可能(?)有聽到所以在 2013-5-7 更新了一個檔案(http://sourceforge.net/projects/appserv/?source=navbar),但我看了之後發現有點怪怪的這個檔案是 2007-07-25 就已經發佈的檔案且沒有更新任何新的內容,但是 SOURCEFORGE 的網站上的時間看起來像是已有更新的樣子。詳細案情就有請各位鍵盤科南幫忙找找原因了。
以上是因為在 2013-05 月時發生了一件大規模的 DDOS 案例影響範圍很廣甚至影響整個 TANET ,直到現在網路內的使用者因為 APPSERV 所造成的電腦問題及網路問題仍十分的頻繁。有的機器表現出來的外顯症狀為 Windows 登入後速度很慢,因為被入侵的主機在開機的時候不斷的重製 IRC 程式並寫入 windows 註冊表。當然各種入侵的方式不一樣,但都是由 APPSERV 懶人包漏洞延伸而來的。另一種是該機器當成網路 Server 不常登入,使用者一點都不感覺他有異狀直到被發資安通報 IP 成為 DDOS 攻擊別人的一份子,最後遇到較糟糕的狀況是引發起另外一團殭屍網路的攻擊,造成整個組織的網路湧入大量的垃圾封包影響所有的網路服務。這是經過幾個月的沈澱後得到的結論:資安通報及中毒現象是其表徵,APPSERV 是根源的一部分。
參考:
1. TACERT http://cert.tanet.edu.tw/pdf/phpmyadmin.pdf
2. EXPLOIT http://www.exploit-db.com/exploits/16913/
----
APPSERV (http://www.appservnetwork.com/)是一個 Windows 下很成功的懶人包專案,它把 Apache 、PHP、MySQL以及 PHPMyAdmin 整合打包成為一個安裝檔案,對於入門的程式開發人員很方便。也因為它在 2006 年就推出所以到現在仍是下載率很高的專案,每個月約有 10 萬次下載。
![]() |
圖1:APPSERV每月下載次數 |
但是問題就在這裡,它目前的版本為 2008-06-10 的版本(http://sourceforge.net/projects/appserv/files/?source=navbar),作者已經有 5 年多沒有更新了,但是還是有那麼多人下載使用。
在 2009 、2010 有很多 phpMyAdmin 的漏洞陸續被公開,以 CVE-2009-1151(http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-1151) 為例,它說明在 phpMyAdmin 的 setup.php 程式中有個程式碼可以寫入檔案的漏洞存在。如果找一下還會發現已經有人將它寫成自動化入侵的工具程式。
![]() |
圖2:CVE-2009-1151自動化入侵工具 |
如果知道漏洞存在並補強其實不會造成什麼問題,但問題在於使用 APPSERV 的大多為初學者或對於系統程式不熟悉的使用者,只求網站能工作不會注意這些細節的問題。如果你用 google 的 inurl + site + intext 搭配搜尋你會發現真的很多人不在意,且甚至把這個網站它放到公開的網路上工作。關鍵字:「phpmyadmin scripts setup.php win32」
![]() |
圖3:google「inurl:phpmyadmin/scripts/ site:edu.tw」 |
![]() |
圖4: 沒有保護的 scripts 目錄,透過 google 就可找到 |
如果稍微有些概念的話你會發現,每月APPSERV 懶人包 10 萬的下載量轉換為殭屍網路主機如果有 1% 轉換成功的話那就是 1000 台主機,所以只要透過 APPSERV 的漏洞幾個月內就可入侵控制數萬台以上的主機,屆時如需要發動網路攻擊也就非常的容易。底下紀錄是我手上隨便一台機器的 apache 紀錄檔,隨便找一下網路上四處都有機器人在掃描這個漏洞。
![]() |
圖5: robot 掃描主機的漏洞紀錄 |
![]() |
圖6 : APPSERV 檢測程式 |
所以這裡要請大家幫忙的是不要在教學、研究及正式網站上使用 APPSERV 了,目前國內的資管、資工科系在網站教學課程上面很多是使用 APPSERV 當作教學練習的工具,且根據我的經驗發現很多大學生、研究生是用 APPSERV 架設網站收集研究資料,顯示該套件已經被很多人接受不易改變。
![]() |
圖7: 網路上的APPSERV 教學文件 |
對於初學者 APPSERV 的替代方案建議可使用 WampServer (http://www.wampserver.com) 或是 XAMPP (http://www.apachefriends.org/zh_tw/xampp-windows.html) ,這些活躍的懶人包套件專案,如果網站是放到公開網路上更是需要注意安全性的細節。
當然,最好的方法是請官方網站的維護者更新修正,我想它可能(?)有聽到所以在 2013-5-7 更新了一個檔案(http://sourceforge.net/projects/appserv/?source=navbar),但我看了之後發現有點怪怪的這個檔案是 2007-07-25 就已經發佈的檔案且沒有更新任何新的內容,但是 SOURCEFORGE 的網站上的時間看起來像是已有更新的樣子。詳細案情就有請各位鍵盤科南幫忙找找原因了。
![]() |
圖8: 目前 sourceforge 上面的 AppServ 專案 Summary 頁面 |
以上是因為在 2013-05 月時發生了一件大規模的 DDOS 案例影響範圍很廣甚至影響整個 TANET ,直到現在網路內的使用者因為 APPSERV 所造成的電腦問題及網路問題仍十分的頻繁。有的機器表現出來的外顯症狀為 Windows 登入後速度很慢,因為被入侵的主機在開機的時候不斷的重製 IRC 程式並寫入 windows 註冊表。當然各種入侵的方式不一樣,但都是由 APPSERV 懶人包漏洞延伸而來的。另一種是該機器當成網路 Server 不常登入,使用者一點都不感覺他有異狀直到被發資安通報 IP 成為 DDOS 攻擊別人的一份子,最後遇到較糟糕的狀況是引發起另外一團殭屍網路的攻擊,造成整個組織的網路湧入大量的垃圾封包影響所有的網路服務。這是經過幾個月的沈澱後得到的結論:資安通報及中毒現象是其表徵,APPSERV 是根源的一部分。
參考:
1. TACERT http://cert.tanet.edu.tw/pdf/phpmyadmin.pdf
2. EXPLOIT http://www.exploit-db.com/exploits/16913/
2012/09/13
OCI for PHP 安裝 in CENTOS6 x86_64
ORACLE 的 php 支援說明
http://www.oracle.com/technetwork/topics/php/downloads/index.html
需要先安裝 Oracle Database Instant Client
http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html
下載,他會依據作業系統給你載點,並且要求你登入 oracle (免費註冊)
http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html
請抓取 basic 及 devel 這兩個檔案
[root@power app]# rpm -ivh oracle-instantclient11.2-basic-11.2.0.3.0-1.x86_64.rpm
[root@power app]# rpm -ivh oracle-instantclient11.2-devel-11.2.0.3.0-1.x86_64.rpm
# 安裝 php-devel 、php-pear 以及 gcc 編譯套件
[root@power app]# yum install php-devel php-pear gcc
# 使用 pecl 直接安裝 http://pecl.php.net/package/oci8 ,這是一個 PHP 的元件,會需要編譯所以需要上面兩個 oracle instat client 套件的資料
[root@power app]# pecl install oci8WARNING: channel "pecl.php.net" has updated its protocols, use "pecl channel-update pecl.php.net" to update
downloading oci8-2.0.6.tgz ...
Starting to download oci8-2.0.6.tgz (189,668 bytes)
.....................................done: 189,668 bytes
11 source files, building
running: phpize
Configuring for:
PHP Api Version: 20090626
Zend Module Api No: 20090626
Zend Extension Api No: 220090626
Please provide the path to the ORACLE_HOME directory. Use 'instantclient,/path/to/instant/client/lib' if you're compiling with Oracle Instant Client [autodetect] : <-- enter="" font="">-->
省略 n 行....
Build process completed successfully
Installing '/usr/lib64/php/modules/oci8.so'
install ok: channel://pecl.php.net/oci8-2.0.6
configuration option "php_ini" is not set to php.ini location
You should add "extension=oci8.so" to php.ini
# 編譯完成後請將 extension=oci8.so 這一行加入 /etc/php.ini
[root@power app]# vim /etc/php.ini
extension=oci8.so
# 重新啟動 httpd
[root@power app]# /etc/init.d/httpd restart
# 觀看 phpinfo(); 程式的內容,應該會看到 oci8 的模組已經被載入內容應該如下列
oci8
OCI8 Support | enabled |
Version | 1.4.7 |
Revision | $Revision: 321634 $ |
Active Persistent Connections | 0 |
Active Connections | 0 |
Oracle Run-time Client Library Version | 11.2.0.3.0 |
Oracle Instant Client Version | 11.2 |
Temporary Lob support | enabled |
Collections support | enabled |
Directive | Local Value | Master Value |
---|---|---|
oci8.connection_class | no value | no value |
oci8.default_prefetch | 100 | 100 |
oci8.events | Off | Off |
oci8.max_persistent | -1 | -1 |
oci8.old_oci_close_semantics | Off | Off |
oci8.persistent_timeout | -1 | -1 |
oci8.ping_interval | 60 | 60 |
oci8.privileged_connect | Off | Off |
oci8.statement_cache_size | 20 | 20 |
# 那就寫程式去巴!!! 請參考 php oci 的說明
http://www.php.net/manual/zh/function.oci-connect.php
2012/08/26
Doku WIKI 安裝(CENTOS 6 with SELinux)
Doku WIKI安裝
- Doku wiki 是一套免用資料庫的 wiki 套件,他需要的程式語言為 PHP 安裝、使用、備份都很方便。底下案例以 Doku wiki 的安裝在 student 的個人網頁目錄內為範例說明,此範例是在 SELinux 打開的狀況下安裝,過程中會遇到 SELinux 的問題並且排除該問題。
- 此範例 http://person250.example.com 虛擬主機已經設定對應 http://person250.example.com/~student/ 個人目錄(/home/student/public_html) 並且整個路徑目錄為 755 ,並開啟 SELinux 的 setsebool -P httpd_enable_homedirs=1 讓個人網頁目錄可以正常工作。
- DokuWIKI官網:https://www.dokuwiki.org/dokuwiki 免資料庫的 wiki 程式, 使用 student 身份。
# 請上官方網站抓下最新的檔案,必且放到該目錄底下,請確定已經設定好個人的網頁目錄了。 [student@demo public_html]$ pwd /home/student/public_html [student@demo public_html]$ wget http://www.splitbrain.org/_media/projects/dokuwiki/dokuwiki-2012-01-25b.tgz [student@demo public_html]$ tar zxvf dokuwiki-2012-01-25b [student@demo public_html]$ mv dokuwiki-2012-01-25b wiki
- 觀看duki wiki http://person250.example.com/wiki 網頁,點選 run install並依據提示修正目錄權限
- student 身份
[student@demo public_html]$ chmod 777 wiki/conf/
- 再次觀看duki wiki http://person250.example.com/wiki/install.php
- 使用 root 使用者觀看並修正問題
# 觀看 /var/log/messages 有產生 selinux 警告 root@demo public_html]# tail /var/log/messages ....略.... Aug 26 16:03:47 demo setroubleshoot: SELinux is preventing /usr/sbin/httpd "add_name" access on page.idx. For complete SELinux messages. run sealert -l a5821478-152b-46bb-892d-633ca202b0f8 # 觀看訊息內容 [root@demo public_html]# sealert -l 21c6b959-1cae-4f30-814e-0ecab713f86f Summary: SELinux is preventing /usr/sbin/httpd "write" access on conf. Detailed Description: [SELinux is in permissive mode. This access was not denied.] SELinux denied access requested by httpd. It is not expected that this access is required by httpd and this access may signal an intrusion attempt. It is also possible that the specific version or configuration of the application is causing it to require additional access. Allowing Access: You can generate a local policy module to allow this access - see FAQ (http://docs.fedoraproject.org/selinux-faq-fc5/#id2961385) Please file a bug report. Additional Information: Source Context unconfined_u:system_r:httpd_t:s0 Target Context unconfined_u:object_r:user_home_t:s0 Target Objects conf [ dir ] Source httpd Source Path /usr/sbin/httpd PortHost demo.example.com Source RPM Packages httpd-2.2.15-5.el6 Target RPM Packages Policy RPM selinux-policy-3.7.19-54.el6 Selinux Enabled True Policy Type targeted Enforcing Mode Permissive Plugin Name catchall Host Name demo.example.com Platform Linux demo.example.com 2.6.32-71.el6.x86_64 #1 SMP Wed Sep 1 01:33:01 EDT 2010 x86_64 x86_64 Alert Count 3 First Seen Sun Aug 26 15:59:59 2012 Last Seen Sun Aug 26 16:02:32 2012 Local ID 21c6b959-1cae-4f30-814e-0ecab713f86f Line Numbers Raw Audit Messages node=demo.example.com type=AVC msg=audit(1345968152.291:113): avc: denied { write } for pid=2472 comm="httpd" name="conf" dev=dm-2 ino=2778 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir node=demo.example.com type=SYSCALL msg=audit(1345968152.291:113): arch=c000003e syscall=21 success=yes exit=0 a0=7ff4e47fa080 a1=2 a2=0 a3=7ff4e46343e0 items=0 ppid=2466 pid=2472 auid=0 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=1 comm="httpd" exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null) # 提示沒有明確建議,直接用下列方式修正將檔案設定為 httpd_sys_content_t 的type屬性,再試試看。 [root@demo ~]# chcon --reference=/var/www/html /home/student/public_html/ -R
- 再次觀看duki wiki 的 install 頁面 http://person250.example.com/wiki/install.php
- 切換為 student 身份,修正其他的權限
[student@demo public_html]$ pwd /home/student/public_html [student@demo public_html]$ chmod 777 wiki/conf/ [student@demo public_html]$ chmod 777 wiki/data/ [student@demo public_html]$ chmod 777 wiki/data/pages/ [student@demo public_html]$ chmod 777 wiki/data/attic/ [student@demo public_html]$ chmod 777 wiki/data/media [student@demo public_html]$ chmod 777 wiki/data/media_attic [student@demo public_html]$ chmod 777 wiki/data/media_meta [student@demo public_html]$ chmod 777 wiki/data/meta [student@demo public_html]$ chmod 777 wiki/data/cache [student@demo public_html]$ chmod 777 wiki/data/locks [student@demo public_html]$ chmod 777 wiki/data/index [student@demo public_html]$ chmod 777 wiki/data/tmp
- reload 網頁,發現所有問題已經排除,繼續下一頁安裝。
- 刪除 install.php 避免產生安全性問題
[student@demo wiki]$ rm install.php
- 安裝完成, enjoy it!!
2010/10/25
php list 的 url cache 及 footer 問題
php list 中可以插入遠端的 URL 當作郵件內容,但是內容只要輸入後會被 cache 在 mysql 資料庫中
資料表示 url_cache 如果想立即生效可以從 sql 中刪除被 cache 的 web url 文件
,但是 url cache refetch time 是可以設定的,預設是 3600 秒,只要修改
phplist 目錄中 config/config.php 檔案中的這一段就可以達成
另外在系統中,會自動增加 phplist 的廣告及 footer 訂閱的連結,如果想拿掉可以
修改 admin/sendemaillis.php 其中程式碼為
在 footer 產生訂閱連結的部分,可以修改
資料表示 url_cache 如果想立即生效可以從 sql 中刪除被 cache 的 web url 文件
,但是 url cache refetch time 是可以設定的,預設是 3600 秒,只要修改
phplist 目錄中 config/config.php 檔案中的這一段就可以達成
# send a webpage. You can send the contents of a webpage, by adding
# [URL:http://website/file.html] as the content of a message. This can also be personalised
# for users by using eg
# [URL:http://website/file.html?email=[email]]
# the timeout for refetching a URL can be defined here. When the last time a URL has been
# fetched exceeds this time, the URL will be refetched. This is in seconds, 3600 is an hour
# this only affects sending within the same "process queue". If a new process queue is started
# the URL will be fetched the first time anyway. Therefore this is only useful is processing
# your queue takes longer than the time identified here.
define('REMOTE_URL_REFETCH_TIMEOUT',300);
另外在系統中,會自動增加 phplist 的廣告及 footer 訂閱的連結,如果想拿掉可以
修改 admin/sendemaillis.php 其中程式碼為
$url = getConfig("subscribeurl");$sep = ereg('\?',$url)?'&':'?';
$html["subscribe"] = sprintf('<a href="%s">%s</a>',$url,$strThisLink);
$text["subscribe"] = sprintf('%s',$url);
$html["subscribeurl"] = sprintf('%s',$url);
$text["subscribeurl"] = sprintf('%s',$url);
#?mid=1&id=1&uid=a9f35f130593a3d6b89cfe5cfb32a0d8&p=forward&email=michiel%40tincan.co.uk&
$url = getConfig("forwardurl");$sep = ereg('\?',$url)?'&':'?';
$html["forward"] = sprintf('<a href="%s%suid=%s&mid=%d">%s</a>',$url,$sep,$hash,$messageid,$strThisLink);
$text["forward"] = sprintf('%s%suid=%s&mid=%d',$url,$sep,$hash,$messageid);
$html["forwardurl"] = sprintf('%s%suid=%s&mid=%d',$url,$sep,$hash,$messageid);
$text["forwardurl"] = $text["forward"];
$url = getConfig("forwardurl");
# make sure there are no newlines, otherwise they get turned into <br/>s
$html["forwardform"] = sprintf('<form method="get" action="%s" name="forwardform" class="forwardform"><input type=hidden name="uid" value="%s" /><input type=hidden name="mid" value="%d" /><input type=hidden name="p" value="forward" /><input type=text name="email" value="" class="forwardinput" /><input name="Send" type="submit" value="%s" class="forwardsubmit"/></form>',$url,$hash,$messageid,$GLOBALS['strForward']);
// $text["signature"] = "\n\n--\nPowered by PHPlist, www.phplist.com --\n\n";
// skip by mtchang 2010.7.14$text["signature"] = 'mtchang';
及
/* skip by mtchang 2010.7.14if (!EMAILTEXTCREDITS) {$html["signature"] = $PoweredByImage;#'<div align="center" id="signature"><a href="http://www.phplist.com/"><img alt="Powered by PHPlist" border="0" height="31" src="powerphplist.png" title="Powered by PHPlist" width="88" /></a></div>';# oops, accidentally became spyware, never intended that, so take it out again :-)$html["signature"] = preg_replace('/src=".*power-phplist.png"/','src="powerphplist.png"',$html["signature"]);} else {$html["signature"] = $PoweredByText;}*/$html["signature"] = '';
在 footer 產生訂閱連結的部分,可以修改
$text["footer"] = eregi_replace("\[SUBSCRIBE\]",$text["subscribe"],$text['footer']);
$html["footer"] = eregi_replace("\[SUBSCRIBE\]",$html["subscribe"],$html['footer']);
$text["footer"] = eregi_replace("\[PREFERENCES\]",$text["preferences"],$text["footer"]);
$html["footer"] = eregi_replace("\[PREFERENCES\]",$html["preferences"],$html["footer"]);
$text["footer"] = eregi_replace("\[FORWARD\]",$text["forward"],$text["footer"]);
$html["footer"] = eregi_replace("\[FORWARD\]",$html["forward"],$html["footer"]);
$html["footer"] = eregi_replace("\[FORWARDFORM\]",$html["forwardform"],$html["footer"]);
$text["footer"] = eregi_replace("\[BLACKLIST\]",$text["blacklist"],$text['footer']);
$html["footer"] = eregi_replace("\[BLACKLIST\]",$html["blacklist"],$html['footer']);
if (sizeof($forwardedby) && isset($forwardedby['email'])) {
$htmlmessage = eregi_replace("\[FORWARDEDBY]",$forwardedby["email"],$htmlmessage);
$textmessage = eregi_replace("\[FORWARDEDBY]",$forwardedby["email"],$textmessage);
$html["footer"] = eregi_replace("\[FORWARDEDBY]",$forwardedby["email"],$html["footer"]);
$text["footer"] = eregi_replace("\[FORWARDEDBY]",$forwardedby["email"],$text["footer"]);
$text["footer"] = eregi_replace("\[UNSUBSCRIBE\]",$text["blacklist"],$text['footer']);
$html["footer"] = eregi_replace("\[UNSUBSCRIBE\]",$html["blacklist"],$html['footer']);
} else {
$text["footer"] = eregi_replace("\[UNSUBSCRIBE\]",$text["unsubscribe"],$text['footer']);
$html["footer"] = eregi_replace("\[UNSUBSCRIBE\]",$html["unsubscribe"],$html['footer']);
}
$html["footer"] = '<div class="emailfooter">'.nl2br($html["footer"]).'</div>';
// skip footer by mtchang 2010.10.25$html["footer"] = '';
標籤:
opensource,
php,
phplist
2010/09/28
PHPLIST 使用及設定 - 發信設定
phplist 是一套功能很強大的發信工具,但他的製報功能不是很強.....
http://www.phplist.com/
這是他的特色(官方網站說明)
連台大的的電子發報平台都是用它改寫的
http://epaper.ntu.edu.tw/
他的安裝請參考官方網站的說明,中文有空我在來寫
http://docs.phplist.com/PhplistInstallation
我要備註的是這一段,關於 README.commandline 的設定方式
官方的文件是這樣寫的
* 於是我在我的命令列下這樣的指令 /bin/phplist -p processqueue (處理電子報queue 的信件),它執行了一段時間,因為我設定發 300 封信後,需要休息 300 秒才可以繼續在工作,免得被當成廣告信件。如果這個動作在網頁上執行,它就會把該網頁綁住,然後一直的用 javascript 跑一個執行寄信的畫面,並且鎖住 browser 避免你關掉。但是如果可以把這一段寫成 cron(排成) 放在系統中讓他自己跑就會方便許多了。
* 但是有想到另外一個問題,就是當一個發信的工作跑了很久可能需超過 24 hr 以上的時間發信,系統的處理是等待.....,所以這樣就不會有搶工作佇列的問題。
* 所以如果第二次發信的時候,phplist 會把剛剛發過得扣除,然後在發一次然後在等待 300 秒才會結束程式。所以看起來如果要自動跑的話寫 5min 跑一次,看起來是可以接受的。
* 如果你有設定好的話,它應該會發一封信到你的信箱去,告訴你大概做了什事....
* 但是你知道發信總是有人的 email 會是錯誤的,所以要定時的收取退件清單。這些清單會被收進系統的資料庫內,並且予以紀錄。只要修正這些原始的資料,就可以排除了
* 於是乎加上了排成,我寫成這樣的方式,使用這 epaper 使用 crontab -e 編輯 crontab ,每 20 min 收一次退信,每 5 min 處理信件佇列。
* BUT 人生就是因為有那麼多的 but 才顯得有趣,系統會告訴你某個變數沒有定義,不讓你跑....錯誤訊息如下
* 那怎麼辦勒,只好自己手工產生變數了...於是我修改了 cron 並自己改寫了一個 shell script
* 排成改了變成這樣
* 另外系統為了避免你一直 try 錯誤的信箱,於是有個文件 README.bounces 可以設定當遇到多少次退信後就不再嘗試寄信了。
* 關於 bounces 的處理,需要建立一個帳號,來收取信件處理。設定檔一樣在 config.php 內
* 關於批次處理信件的設定,在設定檔 epaper@www:~/public_html/lists/config$ vim config.php ,可以避免你發信太快被人一直退信或當成垃圾。
http://www.phplist.com/
這是他的特色(官方網站說明)
- phplist is a one-way email announcement delivery system. It is great for newsletters, publicity lists, notifications, and many other uses. (It is different from group mailing list systems like mailman.)
- The Web Interface lets you write and send messages, and manage phplist over the internet.
- phplist keeps sending messages from your web server, even after you shut down your computer.
- 100 000 + subscribers. phplist is designed to manage mailing lists with hundreds of thousands of subscribers. phplist is excellent with smaller lists too!
- No duplicate messages. No 'forgotten' messages. phplist manages message delivery with a message queue, ensuring that every subscriber gets the email message, and that no subscribers receive two copies, even if they're subscribed to more than one list!
- Open/View Tracking tells you how many users opened your email message. This provides a minimum statistic, as many email clients with privacy or security policies block images (gmail, thunderbird, and others).
- Click Tracking tracks links and URLs. Statistics can be viewed by message, URL or subscriber.
- Multiple Subscribe Pages allow you to choose many different combinations of templates, languages, user attributes and lists.
- Templates are completely customizable, and make site integration a breeze.
- Multiple Templates on different subscribe pages can integrate phplist with several different web sites.
- Subscriber Attributes like 'name', 'country', and other personal information, are completely customizable. You can specify what information you need to get from users when they subscribe.
- User Specific Content. You can use Subscriber Attributes in message content to make each and every email message personalized with the subscribers name, country, or any other attribute.
- HTML email messages. Subscribers can be given the choice between text or html email messages. You decide whether subscribers can choose, what the default choice is, and what format a message is sent in: text only, html only, or both!
- The HTML Editor allows you to edit html messages from phplist using FCKeditor. TinyMCE is also available.
- Internationalization. phplist is available in English, French, German, Spanish, Portuguese, Traditional Chinese, Dutch, Vietname and Japanese and translation work is in progress for other languages.
- Easy Install via Fantastico, FTP upload, or SSH.
- Multiple List Administrators. The super-admin can assign lists to List Managers, who can manage their users and lists. The super-admin user can 'prepare' messages that can be sent by list managers to their lists.
- Subscriber Preferences. Every email message contains personalized URLs for subscribers to update their preferences or unsubscribe. Subscribers can update their own information and keep your database up to date. Unlike most other mailing list managers, in phplist subscribers can change their email address.
- The User Management tools are excellent to manage and maintain large databases of subscribers.
- Bounce Processing keeps your database clean of unused and non-existent email addresses.
- Advanced Bounce handling let's you teach phplist to distinguish between permanent and temporary message-delivery errors. You can define automated actions on receipt of bounce messages according to matches with your regular expressions.
- CSV Import and Export. Use CSV and tab delimited files to import your existing list of users or to export the users on the phplist system for use in your in-house database. phplist's database has a 'foreign key' to help keep multiple copies of databases synchronized without duplicating users.
- Attachments can be uploaded and included in messages for download.
- Send a Web page. Tell phplist the URL of a web page you want to send to your users, and phplist will fetch it and send it. You can even put subscriber-specific parameters in the URL.
- RSS feeds can be automatically sent to a mailing list weekly, daily, or monthly.
- PDF messages can be automatically created and sent as attachments to ensure that your message is seen the way it was designed by all your subscribers, regardless of their email message reader.
- Batch Processing is useful in shared hosting environments. Set the maximum number of sent messages in a given time period.
- Throttling can limit the load on your server so it doesn't overload.
- Domain Throttling limits the number of emails to specific domains to keep on the friendly side of their system administrators.
- Scheduled Sending let's you tell phplist when the message is to be sent.
- Repetition. A message can be repeated automatically to send updated dynamic content and attachments.
- Text from HTML. Text email messages are managed fluently in phplist. phplist will automatically create a text version of an html message. Optionally the message composer can create it manually.
- PGP signing and encrypting (soon).
Send your message digitally signed or encrypted, or both. - Email to Fax (soon).
Configure the details of your favourite email 2 fax gateway and phplist will send the HTML version of the message as a PDF attachment to your fax gateway. The fax will include the images in the HTML. - Integration with other tools. Several systems exist on the internet that integrate phplist with your favourite CMS or blogging tool. Check out the Documentation for a list.
連台大的的電子發報平台都是用它改寫的
http://epaper.ntu.edu.tw/
他的安裝請參考官方網站的說明,中文有空我在來寫
http://docs.phplist.com/PhplistInstallation
我要備註的是這一段,關於 README.commandline 的設定方式
官方的文件是這樣寫的
Running PHPlist from the commandline
Commandline processing requires PHP 4.3.0 or higher
A few pages in the PHPlist system can now, as of version 2.7.0 be run with
a simple command from the commandline.
the script to use is called "phplist" in the "bin" directory. You will have to edit
this script to fit your system
The normal PHPlist access restrictions are bypassed, but the Unix users who are
allowed to run the script should be mentioned in the "commandline_users" config
variable. The identity of a user is determined by the USER environment variable, which
may not always match your system.
The "p" parameter is the page that needs to be run.
Currently you can use "send", "processqueue" and "processbounces"
phplist -psend
This will require some more arguments:
-l list
-s subject
[-f from]
and you need to "pipe" the message into the script.
The -l parameter can have two types of values, the name of the list or the number of the list.
You can added multiple lists or multiple -l parameters
The subject can have spaces
The from is optional. It will default to the system administrator as set up in your config.
So the full "send" command line would be:
phplist -psend -s This is the subject -l test 1 2 3 -f me@server.com < messagefile
* 於是我在我的命令列下這樣的指令 /bin/phplist -p processqueue (處理電子報queue 的信件),它執行了一段時間,因為我設定發 300 封信後,需要休息 300 秒才可以繼續在工作,免得被當成廣告信件。如果這個動作在網頁上執行,它就會把該網頁綁住,然後一直的用 javascript 跑一個執行寄信的畫面,並且鎖住 browser 避免你關掉。但是如果可以把這一段寫成 cron(排成) 放在系統中讓他自己跑就會方便許多了。
epaper@www:~$ /home/epaper/bin/phplist -p processqueue
PHPlist version 2.10.12 (c) 2000-2010 Tincan Ltd, http://www.phplist.com
Started
Sending in batches of 300 emails
Script stage: 6
Finished, Nothing to do
Finished, All done
epaper@www:~$ /home/epaper/bin/phplist -p processqueue
PHPlist version 2.10.12 (c) 2000-2010 Tincan Ltd, http://www.phplist.com
Started
Sending in batches of 300 emails
Processing has started, 1 message(s) to process.
Processing message 66
Looking for users
Found them: 778 to process
batch limit reached: 300 (300)
Script stage: 5
300 messages sent in 335.89 seconds (3215 msgs/hr)
1 invalid emails
Finished this run
Reload required
You have mail in /var/mail/epaper
* 但是有想到另外一個問題,就是當一個發信的工作跑了很久可能需超過 24 hr 以上的時間發信,系統的處理是等待.....,所以這樣就不會有搶工作佇列的問題。
epaper@www:~$ /home/epaper/bin/phplist -p processqueue
PHPlist version 2.10.12 (c) 2000-2010 Tincan Ltd, http://www.phplist.com
A process for this page is already running and it was still alive 1 seconds ago
Running commandline, quitting. We'll find out what to do in the next run.
* 所以如果第二次發信的時候,phplist 會把剛剛發過得扣除,然後在發一次然後在等待 300 秒才會結束程式。所以看起來如果要自動跑的話寫 5min 跑一次,看起來是可以接受的。
epaper@www:~$ /home/epaper/bin/phplist -p processqueue
PHPlist version 2.10.12 (c) 2000-2010 Tincan Ltd, http://www.phplist.com
Started
Sending in batches of 300 emails
Processing has started, 1 message(s) to process.
Processing message 66
Looking for users
Found them: 477 to process
* 如果你有設定好的話,它應該會發一封信到你的信箱去,告訴你大概做了什事....
To: epaper@epaper.cm.nsysu.edu.tw
Subject: PHPlist Maillist Processing info
Recieved:
From: EpaperWebmaster
X-MessageID: systemmessage
X-ListMember: epaper@epaper.jangmt.com
X-UID: 4790
Started
Sending in batches of 300 emails
Processing has started, 1 message(s) to process.
Processing message 66
Looking for users
Found them: 778 to process
batch limit reached: 300 (300)
Script stage: 5
300 messages sent in 335.89 seconds (3215 msgs/hr)
1 invalid emails
* 但是你知道發信總是有人的 email 會是錯誤的,所以要定時的收取退件清單。這些清單會被收進系統的資料庫內,並且予以紀錄。只要修正這些原始的資料,就可以排除了
epaper@www:~$ /home/epaper/bin/phplist -p processbounces
PHPlist version 2.10.12 (c) 2000-2010 Tincan Ltd, http://www.phplist.com
110 bounces to fetch from the mailbox
Please do not interrupt this process
25 done
50 done
75 done
100 done
Closing mailbox, and purging messages
Identifying consecutive bounces
Identifying consecutive bounces
0 of 355 users processed
Identifying consecutive bounces
10 of 355 users processed
Identifying consecutive bounces
* 於是乎加上了排成,我寫成這樣的方式,使用這 epaper 使用 crontab -e 編輯 crontab ,每 20 min 收一次退信,每 5 min 處理信件佇列。
# m h dom mon dow command
*/5 * * * * /home/epaper/bin/phplist -p processbounces
*/20 * * * * /home/epaper/bin/phplist -p processqueue
* BUT 人生就是因為有那麼多的 but 才顯得有趣,系統會告訴你某個變數沒有定義,不讓你跑....錯誤訊息如下
Error: USER environment variable is not defined, cannot do access check. Please make sure USER is defined.
PHPlist version 2.10.12 (c) 2000-2010 Tincan Ltd, http://www.phplist.com
* 那怎麼辦勒,只好自己手工產生變數了...於是我修改了 cron 並自己改寫了一個 shell script
epaper@www:~$ vim epaper_cron.sh
#!/bin/bash
# 手工把變數輸出,應該只是要 USER 這個變數而已...
SHELL=/bin/bash
USER=epaper
MAIL=/var/mail/epaper
PATH=/home/epaper/bin:/usr/local/bin:/usr/bin:/bin:/usr/games
PWD=/home/epaper
LANG=zh_TW.UTF-8
HOME=/home/epaper
LANGUAGE=zh_TW:zh
LOGNAME=epaper
export SHELL
export USER
export MAIL
export PATH
export PWD
export LANG
export HOME
export LANGUAGE
export LOGNAME
/home/epaper/bin/phplist -p processbounces
/home/epaper/bin/phplist -p processqueue
* 排成改了變成這樣
epaper@www:~$ crontab -e* 然後就一切正常了, 可以到 /home/epaper/epaper_cron.log 看系統產生的 log
m h dom mon dow command
*/5 * * * * /home/epaper/epaper_cron.sh >> /home/epaper/epaper_cron.log
* 另外系統為了避免你一直 try 錯誤的信箱,於是有個文件 README.bounces 可以設定當遇到多少次退信後就不再嘗試寄信了。
In the admin pages, you can now load the bounces in the PHPlist database. Some bounces are not.
always really bounces, but they can be "Message delayed" or "Out of Office" messages. Therefore
PHPlist will not immediately unsubscribe a user when a message has bounces, but it will determine
a treshold of messages which will identify a bounce.
You set the threshold with the variable
$bounce_unsubscribe_treshold = 3;
This variable will be used to returns of normal messages. If "systemmessages" return, a user will
be unsubscribed immediately. Unsubscribed means that their email will be marked unconfirmed, which
will cause the system to stop sending emails to this user.
In the future it will become possible to "probe" the unconfirmed emails with a renewed request for
confirmation, which will be dealt with seperately, most likely by simply deleting the user.
If a message to a user bounces, the threshold will be used to determine the previous number of
message that have bounced. A user will only be marked unconfirmed once a row of consecutive messages
as many as your threshold have occurred.
If you run in TEST mode, the emails in the bounce system will not be deleted from the mailbox. If you
have set TEST to 0, it will delete the emails it has dealt with, according to the settings
$bounce_mailbox_purge = 1;
and
$bounce_mailbox_purge_unprocessed = 1;
$bounce_mailbox_purge can be 1 or 0, and 1 means that messages that have been processed and identified
will be delete from the mailbox. $bounce_mailbox_purge_unprocessed can be 1 or 0 as well, and
1 means that also unprocessed messages, which are messages that could not be matched with a user in
the system, will be deleted. This is fairly safe, because you can still look at the messages
in PHPlist.
* 關於 bounces 的處理,需要建立一個帳號,來收取信件處理。設定檔一樣在 config.php 內
=========================================================================
Settings for handling bounces
=========================================================================
*/
# Message envelope. This is the email that system messages come from
# it is useful to make this one where you can process the bounces on
# you will probably get a X-Authentication-Warning in your message
# when using this with sendmail
# NOTE: this is *very* different from the From: line in a message
# to use this feature, uncomment the following line, and change the email address
# to some existing account on your system
# requires PHP version > "4.0.5" and "4.3.1+" without safe_mode
$message_envelope = 'listbounces@epaper.jangmt.com';
# Handling bounces. Check README.bounces for more info
# This can be 'pop' or 'mbox'
$bounce_protocol = 'pop';
# set this to 0, if you set up a cron to download bounces regularly by using the
# commandline option. If this is 0, users cannot run the page from the web
# frontend. Read README.commandline to find out how to set it up on the
# commandline
define ("MANUALLY_PROCESS_BOUNCES",1);
# when the protocol is pop, specify these three
$bounce_mailbox_host = 'epaper.jangmt.com';
$bounce_mailbox_user = 'listbounces';
$bounce_mailbox_password = '1234567890xxxxxx';
# the "port" is the remote port of the connection to retrieve the emails
# the default should be fine but if it doesn't work, you can try the second
# one. To do that, add a # before the first line and take off the one before the
# second line
$bounce_mailbox_port = "110/pop3/notls";
#$bounce_mailbox_port = "110/pop3";
# when the protocol is mbox specify this one
# it needs to be a local file in mbox format, accessible to your webserver user
$bounce_mailbox = '/var/spool/mail/listbounces';
# set this to 0 if you want to keep your messages in the mailbox. this is potentially
# a problem, because bounces will be counted multiple times, so only do this if you are
# testing things.
$bounce_mailbox_purge = 1;
# set this to 0 if you want to keep unprocessed messages in the mailbox. Unprocessed
# messages are messages that could not be matched with a user in the system
# messages are still downloaded into PHPlist, so it is safe to delete them from
# the mailbox and view them in PHPlist
$bounce_mailbox_purge_unprocessed = 1;
# how many bounces in a row need to have occurred for a user to be marked unconfirmed
$bounce_unsubscribe_threshold = 5;
* 關於批次處理信件的設定,在設定檔 epaper@www:~/public_html/lists/config$ vim config.php ,可以避免你發信太快被人一直退信或當成垃圾。
# batch processing
# if you are on a shared host, it will probably be appreciated if you don't send
# out loads of emails in one go. To do this, you can configure batch processing.
# Please note, the following two values can be overridden by your ISP by using
# a server wide configuration. So if you notice these values to be different
# in reality, that may be the case
# define the amount of emails you want to send per period. If 0, batch processing
# is disabled and messages are sent out as fast as possible
# define("MAILQUEUE_BATCH_SIZE",0);
define("MAILQUEUE_BATCH_SIZE",300);
# define the length of one batch processing period, in seconds (3600 is an hour)
# define("MAILQUEUE_BATCH_PERIOD",3600);
define("MAILQUEUE_BATCH_PERIOD",300);
標籤:
linux,
opensource,
php
訂閱:
文章 (Atom)