Tag: php

Check if PHP session has already started

Posted by – January 16, 2014

用 PHP 寫系統基本上躲不掉 session 相關的一系列問題的。因為個人偏好 CodeIgniter,所以很多時候用 Session Library 或是開源的 Native Session Library 就可以避開一些煩瑣的麻煩。

不過很多時候碰到沒有使用 framework 當基礎,直接用 PHP 開發的專案時,程式碼裡 "充斥" 著 session_start() 也是非常普遍的事情,接著就會一直在 error_log 裡看到這樣的訊息:

PHP Notice:  A session had already been started

看了有夠礙眼,也讓人覺得很不專業。

其實這問題是可以避免的。只要在宣告前檢查是否啟動就好。

isset($_SESSION) or session_start();

如果使用的是 PHP 5.4 以上的版面,還有更可靠的寫法。

(session_status() !== PHP_SESSION_ACTIVE) or session_start();

乾乾淨淨的是 error_log 才是開發者的王道。

Disable Cache for PHP 5.5.3 in MAMP

Posted by – January 3, 2014

前些時間接手一個已經上線的案子,進行改版作業。從 Git 上把 code 拉下來,執行一下就... 爆了。發現同事用了相當新的 PHP 語法。我本機的開發環境是 PHP 5.2.x,無法執行。

馬上想到 MAMP 可以切換成新的版本,切換成 5.5.3 問題就解決了。

MAMP PHP version switch More

Bookmark: Hashids, Generate short hashes from numbers

Posted by – October 30, 2013

以前寫過自己的短網址服務,不過那時候很多計算,尤其是網址的編碼都是亂寫一通。跟朋友討論的時候才曉得用 base36 之類的方法編碼。

最近又碰到一個需求,需要將幾組參數編成較短的字串,在 StackOverflow 上亂逛找到了 Hashids 這個好東西。支援多種語言、可自訂 salt,可編多組參數,最重要是這是雙向的,可以解回來。完全符合需求。

Hashids website

ps. 其中 PHP 版的範例有用到 namespace,把源碼的 namespace 註解掉就可以在 PHP 5.3 以下使用。

Codeigniter: Check if libraries/helper/core files is loaded

Posted by – September 13, 2013

使用 CodeIgniter 框架開發時,會透過 $this->load->library() 之類的方法來載入特定的檔案。在 CI 的 routing 規則中,同一個檔案只會被載入一次,因此多寫幾次 $this->load->library() 是不會發生什麼慘劇的。

不過有時候還是想確認到底某 class 有沒有載入過,而不想到處丟 $this->load->xxx() 的話,可以用以下方法來確認。

if (class_exists('Library'))
{
    $this->library->myMethod();
}

要注意的是 CI 有別名的規則,比如說有個 model 叫 'file_model'。使用別名載入時,會寫成以下

$this->load->model('file_model', 'file');
$this->file->do_something();

這種情況下,若要檢查是否已載入,要用原名。如下:

if (class_exists('File_model'))
{
    // do something
}

Fix Sublime Text’s quirky PHP variable selection

Posted by – August 14, 2013

Sublime Text 是近來相當受歡迎的文字編輯器,快速、方便的操作介面對程式開發有很大的助益。這也是我目前在 Mac 上主要的文字編輯器。

不過在開發 PHP 的時候,Sublime Text double click 選字卻不會選到 PHP 變數前的那個 $ 錢字號。一開始還蠻困擾的,但實際用起來好像不太影響我寫程式的流程,所以就放著不管了。

But! 我同事問了... 他說這個讓他很困擾,有沒有辦法在 double click 的時候連 $ 一起選起來。

Sublime Text 幾乎所有的參數都能改,這也是這個編輯器很妙的地方,可以高制客製化。

先開啟 Packages 路徑... Sublime Text > Preferences > Browse Packages...

sublime_text_browse_packages

打開後進入名為 User 的資料夾,新增一個純文字檔,命名 PHP.sublime-settings

裡面貼上這段文字後存檔離開,Sublime Text 會馬上生效。

{
    "word_separators": "./\\()\"'-:,.;<>~!@#%^&*|+=[]{}`~?"
}

這樣點兩下選取變數就會連 $ 一起選起來了。

Run a PHP script from the command line with MAMP

Posted by – August 8, 2013

我在 Mac 上開發 PHP 一直是用 MAMP 這個好用的 App。不過如果碰到需要在 Terminal 下以指令方式執行 PHP 程式就有點麻煩。

MAMP 裡的 php 路徑頗長.... 像這樣...

/Applications/MAMP/bin/php/php5.3.6/bin/php -v # 查詢 PHP 版本

所以還是來修改一下 ~/.bash_profile 吧。如果沒有這個檔案,自己建一個。

在裡面加入這一行…

export PATH=/Applications/MAMP/bin/php/php5.3.6/bin/:$PATH

存檔後離開。

在 Terminal 下輸入

source ~/.bash_profile

會重讀設定檔,然後剛才的修改就生效了。這樣以後要執行 PHP script 直接輸入 php 就可以了,方便許多。

PHP FIG Group PSR standard 程式風格

Posted by – January 25, 2013

這兩天在查資料的時候才知道有 PSR 風格。這是由 PHP FIG Group 所訂的規範。FIG 這個組織是由一群開發 Open Source PHP 專案的開發者所組成,目的在於以最低程度的限制來統一各個專案的 coding style,避免各家自行發展的風格阻礙了程式設計師撰寫的困擾。

PSR 規範有四套,分別為

PSR-0 (Autoloading standard)

PSR-1 (Basic Coding Standard)

PSR-2 (Coding Style Guide)

PSR-3 (Logger Interface)

依順序有繼承性,每一篇都很簡短,蠻建議看看。

PHP: Finding the year quarter for a date

Posted by – November 29, 2012

在工商業應用中,時間紀錄是系統中非常基本的東西,不過時間的表示方法就五花八門了。最近碰到一個需求是同一個時間欄位可能是 Y-m-d (ex. 2012-11-29)、quarter (Q4 2012)、month (Nov 2012),或是 year (2012),甚至是 TBA (to be announced)。

其中轉換成季 (quarter) 會用到一點點技巧,在此筆記如下:

<?
$timestamp = mktime(0, 0, 0, 11, 29, 2012);
echo ceil(date("m", $timestamp)/3);
?>

只要前面再加個 'Q' 就是第幾季了。
在資料庫部份如何分辨客戶是儲存哪種型態,我的做法是多開一個 date_type 的欄位。

CREATE TABLE `calendar` (
	`c_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
	`c_date` date NOT NULL,
	`c_date_type` char(1) NOT NULL DEFAULT 'd',
	PRIMARY KEY (`c_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

然後用以下 function 來轉換日期

function date_converter($date_type, $date){

	$timestamp = strtotime($date);

	switch($date_type){
		case 'd':
			return $date;
			break;
		case 'm':
			return date("Y-m-d", mktime(23, 59, 59, date('m', $timestamp) + 1, 0, date('Y', $timestamp)));
			break;
		case 'q':
			$the_quarter = ceil(date("m", $timestamp)/3);
			return date("Y-m-d", mktime(23, 59, 59, $the_quarter * 3 + 1, 0, date('Y', $timestamp)));
			break;
		case 'y':
			return date("Y-m-d", mktime(23, 59, 59, 12, 31, date('Y', $timestamp)));
			break;
		case 't':
			return '2099-12-31';
			break;
	}
}

最後將轉換後的日期與日期型態一份存入資料庫,讀取時根據型態做切換就可以了。

Updated:

後來又碰到一個需求,碰到資料庫日期相同時,例如季和月兩種日期都是記錄最後一天,Q1 與 March 在資料庫裡都是 3 / 31,排序的時候就有可能出現 Q1, March, Q1, March 交錯的現象。解決方法是在 SELECT ... ORDER BY ... 加個自訂排序,用前述的 date_type 來排列。

SELECT * FROM `calendar` ORDER BY `c_date` ASC, FIELD(`c_date_type`, `d`, `m`, `q`, `y`, `t`)

如此就可以避免不同型態日期交錯的問題。

 

Sharpen an image using PHP and GD

Posted by – September 26, 2012

同事正在開發一個購物平台,店家可以上傳商品照片,由系統自動縮圖到適合版面的大小,不過 resize 後圖片品質明顯下降,於是同事問我有沒有解法。同事問我並不是因為我比較強,只是因為我的位子在他旁邊。

跟同事討論了一下,試用了 imagecopyresizedimagecopyresampled 兩個函式來縮圖,前者的細節比較好,但部份線條出現明顯的變形,後者圖形正確,但看起來比較模糊。所以先用後者縮圖,再想辦法銳化圖片。

印象中 PHP GD Library 並沒有直接提供 sharpen (銳化) 相關的函式,但是 Google 一下,發現有 imageconvolution 濾鏡可以用,真是有趣,沒想到可以自訂濾鏡,以前在學校修過影像處理課程的回憶.... 都忘光光了。還好不難找到幾組範例。

<?php
// create the image resource from a file
$i = imagecreatefromjpeg('otter.jpg');

// define the sharpen matrix
$sharpen = array(
array(0.0, -1.0, 0.0),
array(-1.0, 5.0, -1.0),
array(0.0, -1.0, 0.0)
);

// calculate the sharpen divisor
$divisor = array_sum(array_map('array_sum', $sharpen));

// apply the matrix
imageconvolution($i, $sharpen, $divisor, 0);

// output the image
header('Content-Type: image/jpeg');
imagejpeg($i);
?>

隨便找一張圖做測試,效果如下。

PHP GD Sharpen Comparison

試了幾種參數組合,以下這組效果比較滿意。

array(0.0, -1.0, 0.0),
array(-1.0, 16.0, -1.0),
array(0.0, -1.0, 0.0)

PHP: Constrains a value to not exceed a maximum and minimum value

Posted by – March 19, 2012

幾年前在寫 Processing (P55) 的時候,有個方便的 function 叫 constrain。用法是

constrain(value, min, max)

例如

float mx = constrain(mouseX, 30, 70);

當 mouseX 大於 70 時就回傳 70,小於 30 時就回傳 30,將值限制在 30 ~ 70 這個區間。因為 Processing 大都是拿來寫互動、視覺方面的程式,所以用到此功能的頻率頗高。後來轉換跑道寫其他語言時,發現好像都沒有這個方便的函式。
最近又有 constrain 的需求,想起幾年前見過有人用 min, max 來代替,寫法如下。

<?php
function constrain($value, $min, $max){
    return max( min( $value, $max), $min);
}

echo constrain(29.3, 30, 60);
?>