Archive for the ‘PHP’ Category

post_max_size 不可設定成 2048M

星期六, 五月 29th, 2010

當然,超過 2048M 也不行。

php 的設定值 post_max_size 是設定 POST 可以上傳的最大資料量。通常在處理檔案上傳時會用到此設定。
繼續閱讀 »

小心 PHP 的 ceil() 函式

星期六, 九月 19th, 2009

系統環境: FreeBSD 7.0 + PHP 5.2.6

ceil() 函式會回傳比輸入數值大且最接近輸入數值的整數,簡單地講就是無條件進位函式。官方手冊上的範例:

echo ceil(4.3);    // 5
echo ceil(9.999);  // 10
echo ceil(-3.14);  // -3

但是由於電腦精確度的關係,以下範例會得出錯誤的結果:

echo 100*1.1;          // 110   正確
echo ceil(100*1.1);    // 111   錯誤,怎麼多 1 ???
echo ceil(110);        // 110   正確

修正方式: 把 ceil() 輸入參數先轉成字串即可。

function gceil($x) {
  return ceil( $x . '' );
  // or
  // return ceil( (string) $x );
}

echo 100*1.1;          // 110   正確
echo ceil(100*1.1);    // 111   錯誤
echo gceil(100*1.1);   // 110   正確

http 與 https 間的 session

星期一, 五月 18th, 2009

由於在加密傳輸的 https:// 網頁中,引入未加密傳輸的 http:// 網頁內容,會出現「安全性資訊」警告。因此在 https:// 網站裡,最好不要引入 http:// 的內容,以免造成使用者不便。

但在目前這個充斥著各種 API 與 Widget 的網路環境中,難免會遇到要在 https:// 網頁中引入 http:// 的狀況。在這種情境下,最好的方式是只在有需要加密傳輸的頁面使用 https://,一般較不重要的頁面仍然使用 http://,降低使用者不便。

而在此種狀況下,最大的問題出在 session 是否能在 https:// 與 http:// 間相互傳遞。因為使用者不會希望在 http:// 登入之後,頁面切換到 https:// 又要再登入一次。幸好,如果是同一台網站伺服器,只要是相同的域名,http:// 與 https:// 互相轉換時會共用相同的 session。
繼續閱讀 »

PHP 設定時區

星期日, 五月 17th, 2009

因為代管主機位在國外,因此需要設定 PHP 執行時的時區

// PHP4
putenv('TZ=Asia/Taipei');
 
// PHP5
date_default_timezone_set('Asia/Taipei');
 
// PHP4 && PHP5
if (funcion_exists('date_default_timezone_set')) {
    date_default_timezone_set('Asia/Taipei');
}
else {
    putenv('TZ=Asia/Taipei');
}

時區識別字 (timezone identifier) 請參考: List of Supported Timezones

get_class() in PHP 4 & PHP 5

星期六, 十月 18th, 2008

get_class() 函式可以取得物件的名稱,但是在 PHP 4 和 PHP 5,回傳的物件名稱一個是小寫、一個是有分大小寫。

class Foo {}
$aa = new Foo();
echo get_class($aa);
// in PHP 4.4.8 --> foo (全小寫)
// in PHP 5.2.6 --> Foo (分大小寫)

繼續閱讀 »

iconv 與 NULL

星期四, 九月 25th, 2008

今天在處理一個文字檔匯入的工作,遇到了 iconv 與 NULL 的小狀況,值得留意一下。

由於網頁是 utf-8,而匯入檔是 big5,因此利用 iconv 來做編碼轉換:

$name = iconv('big5', 'utf-8', $name);

這是再標準不過的寫法了。

但是實際執行匯入時,資料有四萬多筆,卻只匯入了一萬多筆就停了。
打開 log 瞧瞧,發現 MySQL 有錯誤訊息:

Column 'name' cannot be null

原來是有的資料 iconv 轉不出來,就回傳 false,然後欄位 name 又設定不可為 NULL,因此 MySQL 就回傳錯誤訊息。

本來想說,把欄位 name 設定成可接受 NULL 就好,
但這樣又會影響到其他程式,如果其他程式沒有考慮到會有 NULL 的狀況,可能會造成錯誤。
因此最好的做法就是改變匯入時的寫法,遇到 false 就賦予空值,多個小步驟就能解決這個問題。

$name = iconv('big5', 'utf-8', $name);
$name = ($name) ? $name : '';

strtotime() + month 要小心!

星期一, 三月 31st, 2008

因故需要找出當月的最後一天,一開始是用以下語法:

$last_day_of_this_month = date("Y-m-d", (mktime(0, 0, 0, date("m", 
strtotime("next month")), 1, date("Y", strtotime("next month")))) - 86400);

由於每個月的天數不一樣,最後一天可能是 28、29、30、31,因此作法是先找出下個月第一天的 unix timestamp,然後減去 86400 秒(一天),再利用 date() 去調整成想要的日期格式。

但是這寫法在今天 2008-03-31 卻出問題,跑出來的結果是 2008-04-30,不是預期的 2008-03-31。
仔細追查,發現問題是出在 strtotime("next month") 這段程式碼。

測試程式碼:

echo date("Y-m-d", strtotime("today")); // 2008-03-31
echo date("Y-m-d", strtotime("+1 month")); // 2008-05-01
echo date("Y-m-d", strtotime("next month")); // 2008-05-01

從這個結果來看,感覺 strtotime() 在處理 +1 month 時,是直接把月份 +1,像是 3 月 31 日就直接變成 4 月 31 日,由於 4 月只有 30 天,就變成 5 月 1 日。

既然 strtotime() 不能用,就換個寫法:

$last_day_of_this_month = date("Y-m-d", (mktime(0,0,0,
(((date("n")+1)>12) ? 1 : date("n")+1),1,date("Y", strtotime("next month"))))-24*60*60);

還是自己算月份比較保險…

附帶一提,在官方手冊上有提到,在 PHP 4.4.0 以前的版本,next 會誤判成 +2,建議使用 +1 取代 next。但我在 4.4.8 和 5.2.5 下測試,結果都是一樣錯。

資料庫比對程式 – diffdb.php

星期一, 九月 17th, 2007

別人寫的總是用不順手,還是自己寫的比較好用。

這程式的目的很簡單,比對兩個資料庫裡的所有資料表,把兩邊不一樣的地方 highlight 出來,可以一目了然地知道那邊不一樣。

使用情境:
一、撰寫程式時常會調整測試資料庫上的資料結構,在程式上線前一定要同步調整上線資料庫的結果,否則程式一上線,系統馬上就會出錯。
二、將程式模組移植到另一個系統時,要先確認兩邊的資料結構是否有差異,如果該有的欄位沒有、或欄位屬性不一致,那麼程式移植過去後一樣會出問題。

Demo: http://weblog.gilbert.tw/public/scripts/diffdb/
Download: http://weblog.gilbert.tw/public/scripts/diffdb/diffdb.zip
這程式是在 FreeBSD 4.11 + PHP 4.4.4 + MySQL 4.0.18 環境下開發測試,有興趣的人請自行下載、修改,不用客氣。

PHP 的 include_path 設定

星期日, 九月 9th, 2007

依據官網的說明:
http://tw.php.net/manual/en/ini.core.php#ini.include-path
include_path 這個設定會決定 require、include、fopen、file、readfile、file_get_contents 這些函式的搜尋檔案時的路徑順序。
設定時各路徑的分隔符號與作業系統的環境變數 PATH 一樣:在 UNIX 下是用冒號( : ),在 Windows 下是用分號( ; )。
引入檔案時,越左邊的路徑越先被搜尋,一旦搜尋到就會停止搜尋,不會繼續往右側的路徑找。

要調整 include_path 設定,可以利用以下方式設定:在
1. 直接修改 php.ini。
2. 修改 Apache 設定檔 httpd.conf 或 .htaccess 檔。
3. 利用 PHP 函式 ini_set() 或 set_include_path()。

補充說明:
1. 路徑名稱中的句點( . ),表示程式執行時的目錄。
2. PHP 執行期間,可以利用 get_include_path() 函式得知目前的 include_path 設定。

PHP 消失的 ?>

星期一, 九月 3rd, 2007

一般 PHP 程式都是以 <?php 開頭,以 ?> 結束。可是不時會發現一些套件裡的 php 檔,沒有用 ?> 結束,感覺好像是漏掉了一樣。
直到最近才瞭解這是怎麼一回事,原來消失的 ?> 是有含意在裡頭的。

寫程式時難免會 include 或 require 其他檔案,對於 php 來說,如果引入的檔案最後有多餘的空白或換行,有時候就會出問題。
舉例來說,假設有兩個程式 inc.php 與 endofphpfile.php,程式內容如下:

1
2
3
4
<?php
// inc.php
$filename = 'php.jpg';
?>
1
2
3
4
5
6
7
8
9
10
11
<?php
// endofphpfile.php
require_once "inc.php";
$size = getimagesize($filename);
$fp = f o p e n($filename, "rb");
if ($size && $fp) {
    h e a d e r ("Content-type: {$size['mime']}");
    f p a s s t h ru ($fp);
    exit;
}
?>

開啟 endofphpfile.php 可以看到 PHP 的 icon(範例一)。

但如果 inc.php 的文末多了一個換行,就像下圖這樣:
20070903_endofphpfile_1rn
這樣也還是可以看到圖檔(範例二)。

可是如果換成是多了兩個換行:
20070903_endofphpfile_2rn
這下就看不到圖檔了(範例三)。

可是如果換成是有三個換行:
20070903_endofphpfile_3rn
一樣看不到圖檔(範例四)。

因此如果把 ?>拿掉呢?
20070903_endofphpfile_0
就能看到原本的圖檔了(範例五)!

其他在下載檔案或直接丟 content 出去的狀況,都會遇到類似的狀況(瀏覽器會先收到額外的換行)。
因此,為了避免引入檔案時衍生的不必要的麻煩,就把 php 檔最後的 ?> 拿掉,避免送出額外的空白或換行。