轉換容量顯示方式 (ex: 15.31GB)
function reable_size($bytes)
{
if ($bytes == 0)
{
return '0 MB';
}
$unit = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB');
$show_size = $bytes / pow(1024, ($i = floor(log($bytes, 1024))));
if (intval($show_size) == $show_size)
{
return $show_size . ' ' . $unit[$i];
}
return number_format($show_size, 2) . ' ' . $unit[$i];
}
IP:
function get_ip()
{
$inspect_type = array(
"HTTP_CLIENT_IP",
"HTTP_X_FORWARDED_FOR",
"HTTP_X_FORWARDED",
"HTTP_X_CLUSTER_CLIENT_IP",
"HTTP_FORWARDED_FOR",
"HTTP_FORWARDED"
);
foreach ($inspect_type as $type)
{
if (array_key_exists($type, $_SERVER))
{
$ips = explode(",", $_SERVER[$type]);
foreach ($ips as $ip)
{
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))
{
return $ip;
}
}
}
}
return $_SERVER["REMOTE_ADDR"];
}
產生唯一字串(共32個小寫英文及數字)
echo md5(uniqid(rand(), TRUE));
產生亂數陣列(每個數字唯一,srand指定亂數產生)
php > $a = range(0, 29);
php > srand(333); <= 隨意指定隨機數字
php > shuffle($a); <= 按照隨機數字做排序
php > echo print_r($a);
Array
(
[0] => 26
[1] => 21
(..略..)
[28] => 15
[29] => 24
)
判斷是否為ajax 傳進來的值(而不是submit傳入)
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']))
{
if (mb_strtoupper($_SERVER['HTTP_X_REQUESTED_WITH']) === "XMLHTTPREQUEST")
{
// do something...
exit;
}
}
日期與時間
設定台北時區
date_default_timezone_set("Asia/Taipei");
現在的時間(秒)
time(); //13551194547
將日期時間轉換為秒
strtotime('05/29/2013');
獲取目前的日期與時間
date('Y-m-d H:i:s'); //2012-12-11 02:55:08
日期加1天、加5個月
date('Y-m-d', strtotime('+1 day')); //加一天
date('Y-m-d', strtotime('+5 month')); //加五個月
將時間(秒)還原回日期與時間正常格式
strftime('%m/%d/%Y %H:%M:%S', 1283846400); //09/07/2010 16:00:00
產生時間數字型態(同strtotime)
mktime(0, 0, 0, date('m'), date('d'), date('Y')) + (60 * 60 * 24 * $day_offset);
Timestamp 產生至小數位
microtime(true); // 1504695682.0988
註: .0000 也不會出錯
1504695796.9996
1504695796.9998
1504695796.9999
1504695797.0001
1504695797.0003
1504695797.0004
1504695867.9995
1504695867.9997
1504695867.9999
1504695868
1504695868.0002
1504695868.0004
1504695868.0005
DateTime 產生至小數位(推薦此方法)
$now = DateTime::createFromFormat('U.u', number_format(microtime(true), 6, '.', ''));
echo $now->format('Y-m-d H:i:s.u')."<br>";
DateTime 產生至小數位 DateTime createFromFormat error: call to a member function format() on boolean
不要用 $now = DateTime::createFromFormat('U.u', microtime(TRUE)) 當0000, $now->format('Y-m-d H:i:s.u') 會得到 fatal error : call to a member function format() on boolean
即使用 if (is_bool($now)) $now = DateTime::createFromFormat('U.u', $aux += 0.001) 在超過 9999 有一段極短的時間日期會是 1970-01-01
2017-08-25 03:06:59.999900
2017-08-25 03:06:59.999900
2017-08-25 03:06:59.999900
1970-01-01 00:00:00.001000
1970-01-01 00:00:00.002000
1970-01-01 00:00:00.003000
1970-01-01 00:00:00.004000
DateTime 使用 time zone
$timezone = new DateTimeZone("Asia/Taipei");
$time = new DateTime("now", $timezone);
$now = $time->format("Y-m-d H:i:s");
DateTime 使用 time zone 取前一分鐘
$timezone = new DateTimeZone("Asia/Taipei");
$time = new DateTime("1 minutes ago", $timezone);
$timestamp = $time->format("YmdHi");
Convert time and date from one time zone to another
$date = new DateTime('2000-01-01', new DateTimeZone('Pacific/Nauru'));
echo $date->format('Y-m-d H:i:sP') . "\n";
$date->setTimezone(new DateTimeZone('Pacific/Chatham'));
echo $date->format('Y-m-d H:i:sP') . "\n";
刪除test.txt檔再將日期寫入test.txt檔100000次
$ts = array_sum(explode(" ", microtime()));
unlink("./test.txt");
for ($i = 0; $i < 100000; ++$i) {
file_put_contents("./test.txt", date("Y-m-d H:i:s"), FILE_APPEND);
}
echo array_sum(explode(" ", microtime())) - $ts, "\n";
FILE_APPEND參數可參考php manual
輸出 csv 供下載
產生時間做為檔名,並且開啟檔案,檔案若不存在會自行建立
$file_name = array_sum(explode(" ", microtime())) . '.csv';
$file_path = '/var/www/csv/' . $file_name;
$fp = fopen($file_path, 'w');
將陣列寫入csv檔
fputcsv($fp, array('field1', 'field2', 'field3');
foreach ($record as $row)
{
fputcsv($fp, array($row[1], $row[2], $row[3]));
}
fclose($fp);
讓瀏覽器可以輸出下載
header('Content-Type: application/csv');
header("Content-Disposition: attachment; filename={$file_name}");
header('Pragma: no-cache');
readfile($file_path);
php 將陣列組回url
EX:
echo urldecode(http_build_query(array('a' => array(1, 2, 3))));
結果 :
a[0]=1&a[1]=2&a[2]=3
uids array :
$uids = ["1","2","4","5"];
echo urldecode(http_build_query(array('uids' => $uids)));
結果 :
uids[0]=1&uids[1]=2&uids[2]=4&uids[3]=5
顯示目錄結構
$dir = dir('/var/www/test');
while ($folder = $dir->read())
{
if ($folder == '.' || $folder == '..')
{
continue;
}
echo "{$folder}\n";
}
php two files combine
$file1_path = '/home/test/test/qq';
$file2 = file_get_contents('/home/test/test/cc');
file_put_contents($file1_path, $file2, FILE_APPEND);
連接 DB 及測試是否正常
建立測試的 DB 及 Table, 並透過 PDO 執行測試結果
sql :
建立 testDB Database 及 tt Table, 及建立一筆測試資料
php :
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'root', '');
$stat = $db->prepare("Select * from tt");
$stat->execute();
$result = $stat->fetchAll();
print_r($result);
$stat = $db->prepare("SELECT * FROM users WHERE account = ? AND password = ?");
$stat->execute(array($account, $password));
$result = $stat->fetch(PDO::FETCH_ASSOC); // 如果沒找到是 false,有的話是 array
Server push by http1.1 chunked (都由 server 推給 client)
view :
<html lang="zh-TW">
<head></head>
<body>
<img src="image server 的連結">
</body>
</html>
image server :
<?php
$boundary = 'thisIsTheBoundary';
header( "Content-Type: multipart/x-mixed-replace; boundary=\"$boundary\"\r\n" );
echo "--$boundary\n" ;
for( $i=1 ; $i<= 10 ; $i++ )
{
echo 'Content-Type: image/jpeg'."\n\n";
echo file_get_contents( "images/$i.jpg" );
echo "\n--$boundary\n" ;
flush();
sleep(1);
}
?>
PHP Memory
function convert($size)
{
$unit=array('b','kb','mb','gb','tb','pb');
return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
}
echo $this->convert(memory_get_usage(true)); // 123 kb
費式數列
function fibonacci($n,$first = 0,$second = 1)
{
$fib = [$first,$second];
for($i=1;$i<$n;$i++)
{
$fib[] = $fib[$i]+$fib[$i-1];
}
return $fib;
}
print_r($this->fibonacci(50));
寄信
PHP 原生 mail 函數是使用 sendmail 來寄送, 請先安裝 sendmail
$email = "test@gmail.com";
$subject = "Test";
$msg = "Hello world!";
$header = "From: Test User<test@gmail.com>\r\n";
$header .= 'Reply-To: test@gmail.com' . "\r\n"; // 預設收件者回覆的對像
$header .= 'Cc: test@example.com' . "\r\n"; // 副本, email 會出現在信的副件上
$header .= 'Bcc: test@example.com' . "\r\n"; // 也是副本, 但 email 不會出現在信的副件上
$header .= "Content-Type: text/html; charset=utf-8\r\n"; // 可使用 HTML Tag
if (mail($email, $subject, $msg, $header))
{
echo "success";
}
else
{
echo "fail";
}
mb_substr 問題
之前碰到一個問題, 在 apache 與 cli 下 mb_substr 的結果不一樣,
如果只是將解析出來的 string 在 log 印出來是長一樣的, 但是將它寫進 file 的話結果就不同了
以下兩個環境解析出來字串的差別, 幾乎長一樣, 不一樣的是在最後面的字元
- apache :
% lt<8b>^@~<8f>¡ÅU¼0^Nß|×ÈI
- cli :
% lt<8b>^@~<8f>¡ÅU¼0^Nß|
最後去查官方文件 string mb_substr ( string $str , int $start [, int $length = NULL [, string $encoding = mb_internal_encoding() ]] )
原來最後一個編碼的參數是抓 PHP 的系統參數, 然候我再把這個參數印出來看
- apache :
UTF-8
- cli :
ISO-8859-1
確認是採用的編碼不同, 造成字串截取的結果不一樣
解決的方法可以設定在系統變數, 或寫在 mb_substr 參數裡或直接設定 mb_internal_encoding('ISO-8859-1');
AES 加解密
- 密鑰 : AES 使用對稱式密鑰,加解密都要用同一把密鑰
- IV (Initialization Vector) : 避免加密結果每次都一樣
- Paadding : 對未加密的資料做填充, 補滿 128 位元, 常見的方式為 PKCS5
example :
$iv_length = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_length, MCRYPT_RAND);
$key = 'test';
$text = 'secret data';
# 加密
$encrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);
echo base64_encode($encrypt) . "\n"; // 0gSYCbCcf/u1S78uIVXWZw==
# 解密
$decrypt = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypt, MCRYPT_MODE_CBC, $iv);
echo $decrypt . "\n"; // secret data
JSONP
protected function _outputJSON($data)
{
$callback = $this->input->get_post('callback', TRUE);
if (empty($callback))
{
header("Content-type: application/json");
}
else
{
header('Content-Type: application/javascript');
}
$json_str = json_encode($data);
echo (empty($callback)) ? $json_str : $callback . "(" . $json_str . ")";
exit;
}
linux 檔案脫逸,支援 windows 支援的符號(也就是除了 \ / : * ? " < > |)
private function _escape_cmd_argv($path)
{
$path = str_replace(
[ ' ', '"', '`', '^', '!', '$', '&', '(', ')', '[', ']', '{', '}', ',', ';', "'"],
['\ ','\"', '\`', '\^', '\!', '\$', '\&', '\(', '\)', '\[', '\]', '\{', '\}', '\,', '\;', "\\'"],
$path
);
return $path;
}
將 JSON 輸出在 html hidden 欄位裡
php :
$convenience_store = [
array(
'value' => 70,
'label' => '7-11',
'formatted' => '12552 間',
),
];
html :
<input type="hidden" id="getData" value=""<?php echo htmlspecialchars($convenience_store, ENT_QUOTES); ?>"/>
注意 htmlspecialchars 的 ENT_QUOTES 參數
js :
var getData = JSON.parse($('#getData').val());
output mp4 - support range
<?php
$file = 'test.mp4';
$fp = @fopen($file, 'rb');
$size = filesize($file); // File size
$length = $size; // Content length
$start = 0; // Start byte
$end = $size - 1; // End byte
header('Content-type: video/mp4');
//header("Accept-Ranges: 0-$length");
header("Accept-Ranges: bytes");
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $start;
$c_end = $end;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
}else{
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $end) ? $end : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
}
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
if ($p + $buffer > $end) {
$buffer = $end - $p + 1;
}
set_time_limit(0);
echo fread($fp, $buffer);
flush();
}
fclose($fp);
exit();
?>
Ref : http://www.tuxxin.com/php-mp4-streaming/
Send a notification to android device.
define("GOOGLE_API_KEY", "***************************************");
define("GOOGLE_GCM_URL", "https://android.googleapis.com/gcm/send");
function send_push_notification($registatoin_ids, $message)
{
$fields = array(
'registration_ids' => $registatoin_ids,
'data' => array('message'=>$message)
);
$headers = array(
'Authorization: key=' . GOOGLE_API_KEY,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, GOOGLE_GCM_URL);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
if ($result === FALSE) {
return array(FALSE, 'curl error : ' . curl_error($ch));
}
curl_close($ch);
$result_arr = json_decode($result, TRUE);
if ( ! $result_arr)
{
return array(FALSE, 'json err : ' . $result);
}
if ($result_arr['success']=='1')
{
return array(TRUE, 'Message successfully delivered');
}
else
{
return array(FALSE, json_encode($result_arr['results']));
}
}
/*
$regids = array('*********************************-Cv4vK8p54hH674CHvCfHQq0_dAw749k********************k6cuKsO_O_riIx_EyFGZEgNrHA**********************');
$message = 'hello world ' . date('Y-m-d H:i:s');
echo "start\n";
list($s, $e) = send_push_notification($regids, $message);
var_dump($s);
echo $e . "\n";
*/
Send a notification to ios device.
function send_notify2APNS($deviceToken, $message, $env = 'development', $debug=FALSE)
{
log_message("INFO", "token is : " . $deviceToken);
$passphrase = '';
$fp = FALSE;
$ctx = stream_context_create();
if ($env == 'development')
{
$pem_file = '/home/qq/pem/jemco_dev_push.pem';
stream_context_set_option($ctx, 'ssl', 'local_cert', $pem_file);
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
}
else
{
return array(FALSE, 'Env is not development');
}
if (!$fp)
{
return array(FALSE, "Failed to connect: $err $errstr");
}
$body['aps'] = array(
'alert' => $message,
'sound' => 'default'
);
$payload = json_encode($body);
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
$result = fwrite($fp, $msg, strlen($msg));
fclose($fp);
return ($result) ? array(TRUE, 'Message successfully delivered') : array(FALSE, 'Message not delivered');
}
/*
$deviceToken = '6529a573393c*********************************27639b';
$message = file_get_contents('http://whatthecommit.com/index.txt');
list($s, $m) = send_notify2APNS($deviceToken, $message);
echo $m . "\n";
*/
php array 處理
確保 json_encode 後不會有索引
array_unique 做 json_encode 時,會得到索引->值, 當其他強型態語言(e.g. golang)在事先指定只接收 array 的話,在 decode 時會出錯, 可以用此方法做 unique 但 encode 不會有 key
array_keys(array_flip($test_array))
array_map(‘strval’, 將 value 都轉成 string,避免值是 int 造成其他強型態語言錯誤
array_map('strval', array_keys(array_flip($test_array)))
curl 上傳
php 5.6 用 @
'image' => '@' . $_FILES['image']['tmp_name'] // e.g. @/tmp/phpDV7N6h
php 7.0 用 CURLFile
'image' => new CURLFile($_FILES['image']['tmp_name'], 'image/jpeg', $_FILES['image']['name']),
code
$post_data = [
'image' => new CURLFile($_FILES['image']['tmp_name'], 'image/jpeg', $_FILES['image']['name']),
];
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => 1, // return response body
CURLOPT_TIMEOUT => 10,
CURLOPT_URL => "http://127.0.0.1:8080/user/avatar/upload",
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $post_data,
]);
$resp_body = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close ($ch);
if ($httpcode == 200)
{
// do something
}
php讀寫檔
/home/user_me/test/t.txt :
line 1
line 2
line 3
line 4
line 5
讀:
$test = fopen('/home/user_me/test/t.txt', 'r');
while ( ! feof($test))
{
echo fgets($test);
}
fclose($test);
feof — Tests for end-of-file on a file pointer
寫:
[1] 將第一行移除
$path = '/home/user_me/test/t.txt';
$contents = file_get_contents($path);
$rows = explode("\n", $contents);
array_shift($rows);
file_put_contents($path , join("\n", $rows));
join — Alias of implode()
[2] 新增到最後一行
$path = '/home/user_me/test/t.txt';
file_put_contents($path, md5(uniqid(rand(), TRUE)), FILE_APPEND);
[3] 控制整份檔案內容
$file_path = '/home/user_me/test/q.txt';
$fp = fopen($file_path, 'w');
$rows[] = 'line1';
$rows[] = 'line2';
$rows[] = 'line3';
fwrite($fp, join("\n", $rows));
fclose($fp);
fputs — Alias of fwrite()
寫 csv 檔:
$file_path = '/home/user_me/test/q.txt';
$fp = fopen($file_path, 'w');
fputcsv($fp, array('field 1', 'field 2', 'field 3'));
fputcsv($fp, array('1', '2', '3'));
fputcsv($fp, array('4', '5', '6'));
fputcsv($fp, array('7', '8', '9'));
fclose($fp);