日期時間選擇器

使用bootstrap-datetimepicker來做出日期時間選擇器

<!DOCTYPE html>
<htmllang="zh-CN">
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript" src="./bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../js/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="../js/bootstrap-datetimepicker.js" charset="UTF-8"></script>
<script type="text/javascript" src="../js/locales/bootstrap-datetimepicker.zh-CN.js" charset="UTF-8"></script>
<script type="text/javascript" src="./Chart.bundle.min.js"></script>
<link href="./bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="../css/bootstrap-datetimepicker.min.css" rel="stylesheet" media="screen">

</head>
<body>
<br/>
<div class="container">
  <div>
    <form action="" class="form-inline"  role="form">
		  <div class="col-sm-12 col-md-2">
            <select name='appleIDOption' id='appleIDOption' class="form-control" >
            <!-- <option value="volvo">Volvo</option>  -->
            </select>     
        </div>   

        <div class="form-group col-sm-12 col-md-9">
            <label for="dtp_input1" class="col-md-2 control-label">开始时间</label>
            <div id="startTime" class="input-group date form_datetime col-md-4" data-date="" data-date-format="yyyy-mm-dd hh:ii" data-link-field="dtp_input1">
                <input class="form-control" size="16" type="text" value="" readonly>
                <span class="input-group-addon"><span class="glyphicon glyphicon-remove"></span></span>
				<span class="input-group-addon"><span class="glyphicon glyphicon-th"></span></span>
            </div>
			<input type="hidden" id="dtp_input1" data-date-format="yyyy-mm-ddThh:ii:ss" value="" />


            <label for="dtp_input2" class="col-md-2 control-label">结束时间</label>
            <div id="endTime" class="input-group date form_datetime col-md-4" data-date="" data-date-format="yyyy-mm-dd hh:ii" data-link-field="dtp_input2">
                <input class="form-control" size="16" type="text" value="" readonly>
                <span class="input-group-addon"><span class="glyphicon glyphicon-remove"></span></span>
				<span class="input-group-addon"><span class="glyphicon glyphicon-th"></span></span>
            </div>
			<input type="hidden" id="dtp_input2" data-date-format="yyyy-mm-ddThh:ii:ss" value="" /><br/>
        </div>		
    </form>	
		  <div class="col-sm-12 col-md-1">
          <button class="btn btn-default" id="query">查询</button>
        </div>
  </div>
</div>

<div id="charts" class="container" style="max-width:1600px;max-height:400px;"></div>

</body>
<script type="text/javascript">
    $('.form_datetime').datetimepicker({
        language:  'zh-CN',
        weekStart: 1,
        todayBtn:  1,
        autoclose: 1,
        todayHighlight: 1,
        startView: 2,
        forceParse: 0
    });

//沒有找到bootstrap-datetimepicker中轉出時間戳的格式,只好自己轉
//datastring後面不加+08:00的話Chrome會用+00:00,導致時間戳有誤
    $('#startTime').datetimepicker().on('hide', function(ev){
        $('#dtp_input1').val(Date.parse($('#dtp_input1').val().replace(' ',"T") + "+08:00"));
    });
    $('#endTime').datetimepicker().on('hide', function(ev){
        $('#dtp_input2').val(Date.parse($('#dtp_input2').val().replace(' ',"T") + "+08:00"));
    });

  $("#query").click(function(){
	    $( "#charts" ).empty();
	    var appleIDSelected = $('#appleIDOption').val();
//	    只取十位就好了
	    var startTime = $('#dtp_input1').val().substr(0,10);
	    var endTime = $('#dtp_input2').val().substr(0,10);
	    var postData = { appleID: appleIDSelected,startTime: startTime,endTime: endTime };
	    var jsonData = $.ajax({
		    url: 'keywordData.php',
		    method: 'POST',
		    data: postData,
		  }).done(function (results) {
//			  prepareChart(results);
		    });
	  });
</script>
</html>

WGS-84 To GCJ-02 經緯度在線轉換

之前一直在用http://api.zdoz.net提供的免費接口做GPS坐標轉火星坐標,也挺好用,直到發現了hiwanz的https://github.com/hiwanz/wgs2mars.js,這樣就可以減少一次網絡請求。

經度Longitude:
緯度Latitude:   
經度Longitude:
緯度Latitude:   

中文WebFont體驗

Webfont中文字體效果

春有百花秋有月

3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679

這裡使用了字蛛來製作中文webfont,它的作用是可以根據需要展現的中文來製作網頁字體文件,這樣就避免了中文字體文件過大的問題。使用字蛛需要Node.js,那麼就來安裝。

CentOS安裝Node.js

由於我已經使用了epel-release庫,所以只要yum install nodejs就搞定了,如果沒有使用epel-release庫,可以通過yum install epel-release來使用。

#查看node.js版本
node --version
#通常我們都需要npm這個包管理器
yum install npm
#我用的CentOS6,默認安裝的版本太低,升級node.js我用的nvm,node版本管理器
#使用下面的命令來安裝給當前用戶(檢查下網址,畢竟是要執行的東西)
curl https://raw.githubusercontent.com/creationix/nvm/v0.13.1/install.sh | bash
#想要使用nvm還有執行下下面命令先
source ~/.bash_profile
#現在可以吃用nvm查看可以安裝的node.js版本了
nvm list-remote
#選擇需要安裝的版本,然後安裝
nvm install v5.12.0
#把5.12.0設置為默認版本
nvm alias default v5.12.0
nvm use v5.12.0

使用字蛛

字蛛的文檔寫的不夠傻瓜,我是試了幾次才成功的,說說我的方法。首先準備好需要的ttf字體文件如OCR.ttf,然後準備一個網頁html文件如下:

<!-- index.html -->
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<style>
@font-face {
  font-family: 'OCR';
  src: url('font/OCR.eot');
  src:
    url('font/OCR.eot?#font-spider') format('embedded-opentype'),
    url('font/OCR.woff') format('woff'),
    url('font/OCR.ttf') format('truetype'),
    url('font/OCR.svg') format('svg');
  font-weight: normal;
  font-style: normal;
}
p {
    font-family: 'OCR';
}
</style>
</head>
<body>
<p>這裡是需要用的字體文件的文字。</p>
</body>
</html>

我新建了一個font文件夾,這樣做出來的字體就會保存在font里而不是覆蓋同目錄下的font文件。原字體文件和html文件和font文件夾處於同一目錄中。接下來就很簡單了,安裝字蛛並執行。

#安装字蛛
npm install font-spider -g
#使用字蛛
font-spider index.html

打開font文件夾,就可以看到生成的各種webfont字體文件了。使用的方法和上面html里是一樣的,就不重複說了。

Vesta面板與WordPress

Hostodo的主機,之前是花落無聲在玩,wupo.info寄存在上面。現在快期後,我續了費,昨天重裝了系統,記錄下。

首先到Vesta面板把網站備份下載下來,可以下做好的備份,也可以當時生成一個新備份。Hostodo重裝系統是很方便的,在後台選版本,然後等個幾分鐘就可以了。VestaCP的安裝也非常簡單,直接按官網首頁的三條命令安裝即可。我不知道默認安裝的組建是怎樣的,反正最後一條安裝的命令,我是在官網主頁生成的安裝參數,選擇的是nginx+php-fpm。安裝很快就完成,中間什麼都不用設,然後登錄VestaCP就可以新增網站了。

由於我之前不是管理員,所以我按之前的,給自己分配了普通用戶名,然後以普通用戶登錄,新增網站,新建數據庫,然後就進phpMyAdmin把之前數據庫導入。把備份的網站的public_html恢復到相應文件夾,這樣普通網站就完成了。VestaCP很方便開啟ssl,我用到是sslforfree提供的Let's Encrypt頒發的三個月免費證書,只要把證書文件粘貼到VestaCP就可以里,非常方便。

最後發現Wordpress前台自定義二級頁面都是VestaCP的404,後台卻完全正常。經過搜索,解決辦法為,在/home/yourName/conf/web/nginx.conf或snginx.conf中添加rewrite語句:

server{
    ……
    location / {
        try_files $uri $uri/ /index.php?$args;
        ……
    }
}

修改文件上傳大小上限

由於我有最高權限,所以我是修改/etc/php.ini來實現的,修改如下參數:

upload_max_filesize = 16M
post_max_size = 32M
max_execution_time = 300

最後在Vesta CP頂部/Server/php-ftm/重啟服務即可。

PHP隨機

最近有一個需求是這樣,數據庫有電影幾百條,預告片幾百條。之前是倒序排列返回給客戶端,這樣所有客戶端就能看到最新的片子和預告片,電影和預告片是兩個接口。現在由於考慮服務器壓力,決定隨機展現影片和預告片給客戶端,兩個接口合併成一個,按ABABAB這樣返回。我的做法是以用戶id加今年的天數作為隨機種子對電影和預告片進行隨機排序,然後截取亂序後的數組進行交叉合併並進行分頁,再返回給客戶端。這樣的效果是同一用戶在同一天打開的列表是一樣的,而且影片條目不會重複。而不同用戶打開的列表卻不一樣。公司項目用的ThinkPHP3.1,看下代碼

//接口urlhttp://domin.com:8042/Video/v1.php?qt=Videolist&pi=2&ps=20&uid=972124678
class ApiVideolistAction extends Action{
function getData(){
    //獲取用戶id,單頁條目數量和第幾頁
    $uid = I("get.uid", "0", "intval");
    $pageSize = I("get.ps", "20", "intval");
    $pageNum = I("get.pi", "1", "intval");
    $model1=new Model();

    $film=$model1->query("SELECT video_static.sid FROM video_static, category_video WHERE category_video.cid = 4 AND video_static.status = 1 AND category_video.vid = video_static.sid ");
    $trailer=$model1->query("SELECT video_static.sid FROM video_static, category_video WHERE category_video.cid = 50 AND video_static.status = 1 AND category_video.vid = video_static.sid ");
    $count = count($film) > count($trailer) ? count($film) : count($trailer);
    $allPage = ceil($count / $pageSize);
    if ($pageNum > 0 && $pageNum <= $allPage) {
        $limit_start = ($pageNum - 1) * $pageSize;
    } else {
            $limit_start = 0;
    }
    $dayNum=(int)date('z');
    //设置隨機種子,只要種子一樣,隨機後的數組就一樣
    srand($uid+$dayNum);
    //打亂數組
    shuffle($film);
    shuffle($trailer);
    //分頁切數組
    $vid_listF=array_slice($film,$limit_start,$pageSize);
    $vid_list1F=array_slice($trailer,$limit_start,$pageSize);
    //交叉合併數組
    $arr = array();
    for($i=0;$i < $pageSize; $i++){
        array_push($arr,$vid_listF&#91;$i&#93;); 
        array_push($arr,$vid_list1F&#91;$i&#93;);
    }
    if (empty($arr)) {
            return array(
                "resultStatus" => 1,
                "allCount" => 0,
                "data" => null
            );
    }
    $data = array();
    foreach ($arr as  $every) {
        //這裡用了ThinkPHP的方法根據sid獲取一條數據
        $find = D('VideoStatic')->find($every['sid']);
        //對數據進行處理的示例
        $find['videuri'] = $find['videuri'] ? "http://" . APP_HOST_NAME . ":8042/" . $find['videuri'] : "";        
        if (empty($find)) { continue; }
        $data[] = array_change_key_case($find, CASE_UPPER);
    }
    $result = array(
            "allCount" => $count,
            "pageCount" => $allPage,
            "pageSize" => $pageSize*2,
            "pageIndex" => $pageNum
    );
    return array(
            "resultStatus" => 1,
            "pinfo" => $result,
            "data" => $data
    );
}
}

既然文章名叫PHP隨機,其實PHP隨機最常用的用法是rand(10,13),它會返回最小10,最大13的整數。

php生成圖片與crontab

PHP生成圖片

//@function.php
//先獲取個GET參數等下寫圖片里
if ($_GET["name"]) {
    $name = htmlspecialchars($_GET["name"]);
} else {
    $name = '';
}
//創建圖像
$img=getImgType($img_path);
$img=createImg($img,$wordsPhoto,$left_px,$top_px,25,0,20,'19f','ARIALUNI');
//保存圖像
$img_info=saveImg($img,'png');

//創建圖像函數
function getImgType($img_path) {
	$img = getimagesize ( $img_path );
	switch ($img [2]) {
		case 1 :
			$img = @imagecreatefromgif ( $img_path );
			break;
		case 2 :
			$img = @imagecreatefromjpeg ( $img_path );
			break;
		case 3 :
			$img = @imagecreatefrompng ( $img_path );
			break;
		default :
			$img = @imagecreatefrompng ( $img_path );
	}
	return $img;
}
//修改圖像函數
function createImg($img, $str, $x, $y, $length = 20, $angle = 0, $size = 12, $color = '39f', $font = 'kanghua') {
	switch ($color) {
		case '19f' :
			$color = imagecolorallocate ( $img, 22, 157, 252 );
			break;
		case 'f37' :
			$color = imagecolorallocate ( $img, 255, 51, 119 );
			break;
		case '63a' :
			$color = imagecolorallocate ( $img, 68, 172, 106 );
			break;
		case 'f90' :
			$color = imagecolorallocate ( $img, 255, 158, 3 );
			break;
		case 'a60' :
			$color = imagecolorallocate ( $img, 172, 106, 0 );
			break;
		case '790' :
			$color = imagecolorallocate ( $img, 113, 149, 13 );
			break;
		case 'fff' :
			$color = imagecolorallocate ( $img, 255, 255, 255 );
			break;
		case '000' :
			$color = imagecolorallocate ( $img, 0, 0, 0 );
			break;
		default :
			$color = imagecolorallocate ( $img, 67, 157, 252 );
	}
	switch ($font) {
		case 'ARIALUNI' :
			$font = './../font/ARIALUNI.ttf';
			break;
		case 'CODE2000' :
			$font = './../font/CODE2000.ttf';
			break;
		case 'SarunsManorah' :
			$font = './../font/SarunsManorah.ttf';
			break;
		case 'FreeSerif' :
			$font = './../font/FreeSerif.ttf';
			break;
		case 'kanghua' :
			$font = './../font/kanghua.ttf';
			break;
		case 'shishang' :
			$font = './../font/shishang.ttf';
			break;
		case 'yahei' :
			$font = './../font/yahei.ttf';
			break;
		default :
			$font = './../a_include/font/kanghua.ttf';
	}
	$str = wordwrap_utf8 ( $str, $length );
	imagettftext ( $img, $size, $angle, $x, $y, $color, $font, $str );
	return $img;
}
//文字换行
function wordwrap_utf8($string, $length = 20, $break = "\n", $cut = false) {
	if ($length == 0) {
		return $string;
	}
	preg_match_all ( '/./u', $string, $matches );
	$s = $matches [0];
	$ct = count ( $s );
	for($i = 0; $i < ceil ( $ct / $length ); $i ++) {
		$ns .= implode ( '', array_slice ( $s, $i * $length, $length ) ) . $break;
	}
	return $ns;
}
function saveImg($img, $type = 'png') {
	$img_url = '';
	$img_name = time ().rand(10,99);
        //php5.5以上才支持webp
	if ($type == 'jpg') {
		$img_url = '/a_cache/' . $img_name . '.jpg';
		$img_filename = dirname ( dirname ( dirname ( __FILE__ ) ) ) . '/a_cache/' . $img_name . '.jpg';
		imagejpeg ( $img, $img_filename );
	} else {
		$img_url = '/a_cache/' . $img_name . '.png';
		$img_filename = dirname ( dirname ( dirname ( __FILE__ ) ) ) . '/a_cache/' . $img_name . '.png';
		imagepng ( $img, $img_filename );
	}
	imagedestroy ( $img );
	$img_info ['img_name'] = $img_name;
	$img_info ['img_url'] = '..' . $img_url;
        return $img_info;
}

網頁展示圖片

//@show.php
require_once 'function.php';

<div style="width:100%;text-align:center;background-color: #58C7C2;padding: 0.52em 0.1em 0.52em 0.1em;">
<img id="res_pic" style="display: block;width: 70%;margin-left: 15%;" src="<?php echo $img_info['img_url'];?>" />
</div>

用corntab定期清理緩存圖片

創建可執行文件/www/del_cache,內容如下,意思是刪除兩天前的文件

#!/bin/bash 
find /path/to/your/a_cache/* -mtime +2 -exec rm -f {} \;

把執行文件加入定時任務

crontab -e
#如果有多個編輯器,可能會讓選擇編輯器,但我CentOS中有nano,並沒有提示,我還是得用vi

修改並把下面一行粘貼到最後,意思是每小時的0分執行一次

00 * * * * /path/to/the/script

有時我們需要每30秒執行一次定時任務,但是crontab只能精確到分,可以這麼做:

* * * * * /path/to/executable param1 param2
* * * * * ( sleep 30 ; /path/to/executable param1 param2 )

這裡還有一個每90秒的例子:

*/3 * * * * /path/to/executable param1 param2
*/3 * * * * ( sleep 90 ; /path/to/executable param1 param2 )

有時我們需要以root用戶來執行crontab中的命令,僅僅切換到root用戶然後使用crontab -e似乎還是不行,後來發現(CentOS下)可以這樣:

nano /etc/crontab
#在這裡編輯需要定時執行的命令,並指定運行命令的用戶
03 * * * * root /path/to/the/script

參考了How to Delete Old Files In A Folder Automatically In LinuxRunning a cron every 30 seconds。對於crontab的寫法,可以到crontab.guru來驗證是否正確。其實我主要是想記錄這一段。

Line分享

製作Line分享按鈕請先參考官方文檔用LINE傳送。簡單說是Line分享只能傳一條文本消息和一個url鏈接。http://形式會先跳轉到Line服務器的一個網頁,讓用戶選擇打開Line還是安裝Line。line://形式則直接打開Line進行分享,但是如果用戶沒有安裝Line則按鈕會沒有反應。

使用中發現,Line對Emoji的支持還是很好的,可以放到分享信息中,可以參見Emojiえもじ。同時還發現Line對url的支持有問題,即url中如果出現非英文字符,Line即會將url中剩餘部分丟棄,造成url丟失數據。其實這個解決起來很簡單,用php自帶的base64函數把中文編碼一下再傳遞就好了。只用base64是不行的,因為裡面會有空格等字符會被Line裁掉,所以在加一層urlencode就好了。

//js中定義好Line的分享鏈接,name用base64加密,下面一行php被wordpress保護機制注釋了。
var urlShare="http://www.55mun.com/gameh5/match3/indexv.php?name=<?php echo urlencode(base64_encode($name));?>";
//php中接收並解析出name
$n=htmlspecialchars(base64_decode(urldecode($_GET["name"])));


Line分享網址抓取錯誤

有次分享網址,抓取到的縮略圖和標題都是網站主頁的信息,後來發現是head裏有一條meta信息導致的,這條meta中的url必須是分享的url,否則line就肯定會按照這個meta中的url來抓取:

<meta http-equiv="mobile-agent" content="format=html5;url=http://thePage.you.wishToShare/">

關注Line@

寫法1:

Follow <a href="line://ti/p/@myLineAtAccount">myLineAtAccount</a>

寫法2:

Follow <a href="intent://ti/p/@myLineAtAccount#Intent;scheme=line;action=android.intent.action.VIEW;category=android.intent.category.BROWSABLE;package=jp.naver.line.android;end">myLineAtAccount</a>