FreeBSD PHP4 PHP5 APACHE1 APACHE22 共存

說明現在公司因為支前專案採用PHP4 APACHE1.3  要轉換到PHP5 APACHE22 其中又不使服務中斷 只好再一台系統上同時安裝兩種

以下只說明 另外安裝的PHP5 APACHE22

安裝apache22
cd /usr/ports/www/apache22
make config PREFIX=/usr/local/apache22 install clean
安裝php5
cd /usr/ports/lang/php5
make config PREFIX=/usr/local/php5 APXS=/usr/local/apache22/sbin/apxs APACHE_VERSION=22 install clean
安裝 PHP5-extions 模組
cd /usr/ports/lang/php5-extensions/
make config PREFIX=/usr/local/php5 LOCALBASE=/usr/local/php5 install

安裝中間如有模組卡住  須先到其模組安裝的PORT  重新安裝

並使用 make PREFIX=/usr/local/php5 LOCALBASE=/usr/local/php5 install FORCE_PKG_REGISTER="yes"

強制安裝  有點暴力@@

php execl dde

<?
$excel =new COM("Excel.Application")or die("Unable to instanciate Excel");
print "Loaded excel,version {$excel->Version}n";
$excel->Visible =0;
$book=$excel->Workbooks->open("c://dde.xls");
$sheet=$book->Worksheets("Sheet1");
$a=$excel->DDEInitiate("Excel","c://dde.xls");
$c =$excel->DDEExecute($a,"A1:D1");
(http://www.GetJetso.com - 著數網) $Range=$sheet->Range("A1:D1");
$cell=$Range->Cells(1,4);
echo $cell->value;
$excel->DDETerminate($a);
$excel->Workbooks->Close();
unset($excel);
unset($a);
?>

ajax跟蹤文件上傳進度條

(文件來源 http://www.ibm.com/developerworks/cn/opensource/os-php-v525/index.html)

2007 年 6 月 08 日

PHP V5.2 為開發人員添加了 hook 以利用實時跟蹤文件上傳進度的功能。本文是  系列文章(共五部分)的第 5 部分,將向您展示如何監視文件上傳並相應地編寫代碼,以及如何創建 PHP 進度條。

Web 2.0 是 Internet 上最炙手可熱的時髦字眼,投資者紛紛把資金投入到涉及這項技術的投資項目中。數以百萬計的 Web 站點和應用程序覆蓋的描述性術語有很多。使用 Web 2.0,我們將描述一類 Web 站點,這些站點都提供了瞭解 Internet 上數以百萬計用戶心聲的途徑。與眾不同之處在於它們全都為用戶提供了交流和分享與共同利益相關的觀點和數據的場所,這些站點可以快速生成大量內容。

每個用戶都將提供某種內容 —— 評論咖啡店、上班路線等。YouTube 在這點上是一個優秀示例,為人們提供一個空間可以上傳視頻並使其他用戶可以觀看這些視頻並提供反饋。YouTube 是 Web 2.0 奉行者的新寵,值得關注的是到目前為止 YouTube 的流行度上升得比 Internet 中的任何一個站點都要快。這種流行度可以歸因於大量各式各樣的內容,以及能夠讓用戶以留言的形式發表自己對內容的看法。並且不僅可以留言,用戶甚至還可以 上傳與視頻相對應的視頻留言。

文本領域

許多接收文件的 Web 站點都會在文本框旁邊安置令人厭惡的 Browse 按鈕,強制要求用戶一次上傳一個文件。這可能要花費很長時間,尤其是在以小型文件組的形式提供視頻、甚至照片或其他項目的情況下。由於每個文件都必須單獨 上傳,因此可能會十分繁瑣。假定上傳超大型文件所花的時間會使耐心不足的用戶感到難以容忍,那麼給這些用戶提供積極反饋避免他們放棄並走開將十分重要。

幸運的是,PHP V5.2 引入到文件上傳過程中的新 hook 使我們可以向用戶實時顯示上傳的進展情況。在本文中,將使用 PHP V5.2 為用戶創建一個進度條。


完整說明

如果安裝並配置了正確的庫,則 PHP V5.2 中的新 「hook」 實際上是在文件傳輸過程中可獲得的數據點。這些新 hook 將使用一種稱為 Alternative PHP Cache 的功能。當 PHP 腳本收到一個上傳文件時,解釋程序將自動檢查 $_POST array 以查找名為 APC_UPLOAD_PROGRESS 的隱藏字段,它將成為緩存變量,存儲關於上傳的信息以便腳本可以訪問上傳文件。當此信息已被緩存並且隨時可以訪問後,可以給用戶提供可視化反饋,從而提高用戶體驗。

我們將介紹 HTML 表單中的 APC 代碼的實現,以及如何在 PHP 中識別該實現及如何訪問緩存的信息。表示此數據有很多方法:從 Ajax 到 FLEX,但是我們要關注的是準備這些前端技術所需的訪問數據的方法。

設置

默 認情況下,PHP V5.2 中的 APC 不啟用。由於新 hook 是 APC 的一部分,因此需要確保安裝擴展並使其可用於 PHP 解釋程序。這將通過下載 php_apc 擴展文件來完成。在我們的例子中,將使用 WAMP 安裝,這是包括 Apache 和 MySQL 的免費獲得打包的 PHP for Windows®。它提供了友好的用戶界面並且由於擁有支持配置選項的菜單而十分易於管理。

要在 WAMP 上設置 APC,請執行以下步驟:

  1. 要下載庫和 WAMP,請參閱。
  2. 安裝 WAMP。
  3. 把 php_apc.dll 文件放到 PHP 的擴展文件夾中。默認情況下,此文件夾為 <wamproot>/php/ext。
  4. 使用系統盤 WAMP 菜單來選擇 PHP settings>PHP Extensions>Add Extension
  5. 在彈出的命令行界面中,鍵入 php_apc.dll 並按 Enter
  6. 使用文本編輯器,打開 <wamproot>/php/php.ini 並添加代碼行 apc.rfc1867 = on(添加到任何位置都可以)。如果要嘗試在本地進行測試並計劃上傳大型文件以便可以實際看到進度,則還需要添加以下指令:apc.max_file_size = 200Mupload_max_filesize = 200Mpost_max_size = 200M。請不要在活動的生成服務器上執行此操作,不過,不這樣做很可能用盡帶寬和磁盤空間配額,更不必說會降低其他人的訪問速度。
  7. 重新啟動 PHP。

APC 現在應當已設置並被初始化。APC 的 RFC1867 特性 —— 使您可以跟蹤文件上傳的特性 —— 現在應當已被啟用為選項,並且應當準備好探究文件上傳以啟用實時狀態。


可接收文件的帳戶

要接收文件,必須先設置接收文件的表單。很方便的是,HTML 附帶了文件的標準字段類型。同所有 HTML 表單字段一樣,它在邏輯上被命名為類型 file。默認情況下,附帶了顯示在塊右側的便捷 Browse 按鈕。
清單 1. upload.php 的 HTML 表單

<?php
   $id = $_GET['id'];
?>

<form enctype="multipart/form-data" id="upload_form"
      action="target.php" method="POST">

<input type="hidden" name="APC_UPLOAD_PROGRESS"
       id="progress_key"  value="<?php echo $id?>"/>

<input type="file" id="test_file" name="test_file"/><br/>

<input onclick="window.parent.startProgress(); return true;"
 type="submit" value="Upload!"/>

</form>

需要為此表單創建一個 PHP 頁面,因為需要使用惟一密鑰來跟蹤上傳。最後,它將是用於調用此頁面作為 GET 值的 URL 的一部分。此數字將是稍後將檢索的 APC 緩存條目密鑰的值。要傳遞該值,表單字段需要有一個擁有特殊名稱的隱藏字段,使 APC 知道它需要保存文件上傳狀態。此字段被稱為 APC_UPLOAD_PROGRESS。這是前述的啟動緩存過程的 hook。為確保 PHP 可以訪問緩存中的正確條目,我們使用檢索到的惟一 ID 作為隱藏字段的值,從而創建該值的密鑰。用戶提交表單後 —— 我們將簡短地處理提交按鈕 —— 瀏覽器將把文件和密鑰作為發送給服務器的 POST 數據的一部分進行發送。

裝入到瀏覽器中後,此頁面應當提供一個非常簡單的表單,如圖 1 所示:
圖 1. 上傳表單
上传表单

要在不重新裝入整個頁面的情況下使用戶可以提交文件,需要把此表單嵌入到另一個文件的 iframe 中。如果嘗試僅使用表單操作頁面 (target.php) 來檢索數據,則無法看到任何緩存信息,因為在上傳完成之前頁面不會返回任何信息。鑑於這個原因,使用此新 hook 的最常見示例都是用 Ajax 編寫的。通過該方法,您可以提交表單並且還可以在同一個窗口中繼續檢查上傳的狀態而無需刷新。

要使腳本運行,需要繼續轉到一個包含頁面,該頁面將設置 iframe 並接收已上傳文件的信息。還需要使用一組 JavaScript 函數來為進度指示器獲得數據以及顯示進度指示器。
捕獲已接收的文件

提交表單中包括文件時,該文件將發送到服務器的臨時位置中,直至它被保存到永久位置。當它在臨時存儲設備中時,可以通過 $_FILES 關聯數組獲得它。使用 PHP 附帶的標準版本文件上傳函數,可以選擇路徑並將這些函數保存到服務器上,或者按自己的需要處理這些函數。
清單 2. target.php 文件

<?php

if($_SERVER['REQUEST_METHOD']=='POST') {
  move_uploaded_file($_FILES["test_file"]["tmp_name"],
  "c:\\sw\\wamp\\www\\" . $_FILES["test_file"]["name"]);
  echo "<p>File uploaded.  Thank you!</p>";
}

?>

首先,查看來自表單的 POST 變量是否已被設定並表示我們已經收到了表單數據。如果收到表單數據,並且但願包括文件,則還應當有一個全局數組 $_FILES。把已上傳的文件移到安全位置,這取決於需要對其採取的操作。在本例中,只需把文件移到 \sw\wamp\www(當然,這是完全任意的位置。請隨意選擇一個所需位置)。完成該操作後,我們將感謝用戶。

在這裡包括實際文件處理主要是為了實現完整性。由於本文講述的是進度條,因此收到實際文件後如何處理它無關緊要。
製作進度條

還將需要一個返回實際上傳進度的腳本。清單 3 顯示了一個非常簡單的版本。
清單 3. getprogress.php 文件

<?php
if(isset($_GET['progress_key'])) {

  $status = apc_fetch('upload_'.$_GET['progress_key']);
  echo $status['current']/$status['total']*100;

}
?>

此腳本首先將查找 progress_key,它是先前討論的 $id 值(不必擔心,您馬上就將看到它的來源)。這將導致調用從 APC 緩存返回數據的 apc_fetch()。我們需要正確的文件信息,因此需要惟一 ID,在本文中表示為 $_GET['progress_key']。調用帶有 upload_xxxxxx 參數的 apc_fetch(),其中 xxxxxx 是惟一 ID;PHP 將自動預先追加 upload_ part。

獲得數據後,可以使用 JSON 擴展給信息設定一種更便於在 JavaScript 中使用的格式並返回整個對象(如果需要)。$status 對象是擁有以下字段的數組:

total
文件的總大小
current
到目前為止收到的文件數
rate
上傳速度(以字節每秒為單位)
filename
文件名
name
變量名
temp_filename
PHP 保存文件的臨時副本的位置
cancel_upload
上傳是已取消 (1),還是未取消 (0)
done
上傳是已完成 (1),還是尚未完成 (0)

在本例中,只需要完成百分比。您可以在自己的應用程序中選擇使用更多信息。
顯示進度條的 JavaScript

現在已經準備好開始構建實際的進度條。為了簡單起見,腳本將使用 CSS 創建一個用於模擬進度條並可以使用 JavaScript 進行控制的 div,如清單 4 所示:
清單 4. 主文件 progress.php

<html>
<head><title>Upload Example</title></head>
<body>

<script type="text/javascript">

var counter = 0;

function startProgress(){
    document.getElementById("progressouter").style.display="block";
    fire();
}

function fire(){
   if (counter < 101){
     document.getElementById("progressinner").style.width =
                                                     counter+"%";
     counter++;
     setTimeout("fire()",100);
   }
}

</script>

<div id="progressouter" style=
    "width: 500px; height: 20px; border: 6px solid red; display:none;">
   <div id="progressinner" style=
       "position: relative; height: 20px; background-color: purple; width: 0%; ">
   </div>
</div>

<span onclick="startProgress()">Start me up!</span>

</body>
</html>

此頁面包含了兩個嵌套的 div 元素,外面的那個用作邊框。腳本將調整內部 div 相對於邊框的大小以顯示進度。當用戶單擊 Start me up! 文本時,startProgress() 腳本將調用 fire() 函數。該函數將檢查計數器的值,並且如果該值尚未超過 100,就把內部 div 設為外部 div 寬度的該百分比值。然後它將增加計數器的值並告訴瀏覽器每十分之一秒就執行一次全部上述過程。

結果將與圖 2 非常相似:
圖 2. 進度條腳本
进度条脚本

現在只需要有一種獲得腳本以更新寬度的方法,此寬度不是任意的數字而是完成百分比。


   

整合

現在剩下的只是要把所有內容 hook 到一起。您可以通過 progress.php 頁面來完成此操作。
清單 5. 最終的 progress.php 頁面

<?php
   $id = uniqid("");
?>
<html>
<head><title>Upload Example</title></head>
<body>

<script src="http://maps.google.com/maps?file=api&v=2&key=<yourkeyhere>"
            type="text/javascript"></script>

<script type="text/javascript">

function getProgress(){
  GDownloadUrl("getprogress.php?progress_key=<?php echo($id)?>",
               function(percent, responseCode) {
                   document.getElementById("progressinner").style.width = percent+"%";
                   if (percent < 100){
                        setTimeout("getProgress()", 100);
                   }
               });

}

function startProgress(){
    document.getElementById("progressouter").style.display="block";
    setTimeout("getProgress()", 1000);
}

</script>

<iframe id="theframe" name="theframe"
        src="upload.php?id=<?php echo($id) ?>"
        style="border: none; height: 100px; width: 400px;" >
</iframe>
<br/><br/>

<div id="progressouter" style=
   "width: 500px; height: 20px; border: 6px solid red; display:none;">
   <div id="progressinner" style=
       "position: relative; height: 20px; background-color: purple; width: 0%; ">
   </div>
</div>

</body>
</html>

從底層開始向上層工作,我們已經添加了嵌入清單 1 中的 upload.php 腳本的 iframe,給它提供了在頁面頂部生成的惟一 ID。

現在,是否還記得該表單中的 Submit 按鈕?

<input onclick="window.parent.startProgress(); return true;"
 type="submit" value="Upload!"/>

該按鈕將完成兩項工作。提交表單,像普通的 Submit 按鈕一樣;但在執行該操作之前,它將在主窗口中調用 startProgress() 腳本。startProgress() 腳本將告訴進度條顯示自身 —— 開始時無顯示屬性,然後告訴瀏覽器等待一秒,然後再執行 getProgress() 腳本。

現在,getProgress() 腳本將使事情變得有趣。記不記得在前面我說過將需要使用 Ajax 或某種類似的方法來檢查文件的進度?對,在本例中,表單將採用捷徑,調用來自 Google Maps API 庫的 GdownloadUrl() 函數(注意,表單將導入位於頁面頂部的庫。您將需要獲得自己的訪問此庫的密鑰,但是它是從 Google 免費獲取的)。

此 函數將下載 URL 的內容 —— 本例中為 getprogress.php 腳本 —— 並執行在其中定義的匿名函數。函數所接受的第一個參數是從 URL 返回的數據,本例中為百分比,以便使用它更新進度條。最後,如果文件尚未完成下載,則告訴瀏覽器每十分之一秒重試一次(在實際情況中,可能無法那麼快地執 行這些調用,但是瀏覽器將盡其所能進行操作)。

最終結果是頁面使用戶可以查看文件正被上傳的進度。
圖 3. Progress.php 的輸出
Progress.php 的输出


 

結束語

在 Web 2.0 的世界裡,我們鼓勵用戶在 Web 站點中彼此提供信息和內容。作為開發人員,我們為人與人之間的這種開放、自由的數據交換創建了一個框架。雖然能實現這種功能的工具很早以前就有了,但是用 戶體驗還沒有達到所能具有的最佳程度。在本文中,您已經看到了向用戶提供實時反饋(尤其是為用戶上傳到站點的信息提供進度條)來提高用戶體驗和應用程序質 量的一些方法。

 關於APC 套件安裝說明

cd /usr/ports/www/pecl-APC
make install clean

安裝之後

************************************************************************
You may edit /usr/local/etc/php.ini to change this variables:

apc.enabled="1″
^^^ -> Default value

apc.shm_size="30″
^^^^ -> Default value

* More information on /usr/local/share/doc/APC/INSTALL

Then restart your web server and consult the output of phpinfo().
If there is an informational section for APC, the installation was
successful.
************************************************************************
遵照說明 編輯PHP.INI

正則表達式學習筆記

(忘了引用頁面)

1、正則表達式的三種形式
首先我們應該知道 Perl 程序中,正則表達式有三種存在形式,他們分別是:

匹配:m/<regexp>/ (還可以簡寫為 /<regexp>/ ,略去 m)

替換:s/<pattern>/<replacement>/

轉化:tr/<pattern>/<replacemnt>/

這 三種形式一般都和 =~ 或 !~ 搭配使用(其中 “=~" 表示相匹配,在整條語句中讀作 does,"!~" 表示不匹配,在整條語句中讀作 doesn’t),並在左側有待處理的標量變量。如果沒有該變量和 =~ !~ 操作符,則默認為處理 $_ 變量中的內容。
另外還有:

foreach (@array) { s/a/b/; } # 此處每次循環將從 @array 數組中取出一個元素存放在 $_ 變量中,並對 $_ 進行替換處理。
while (<FILE>) { print if (m/error/); } # 這一句稍微複雜一些,他將打印 FILE 文件中所有包含 error 字符串的行。

替換操作 s/<pattern>/<replacement>/ 還可以在末尾加上 e 或 g 參數,他們的含義分別為:

s/<pattern>/<replacement>/g 表示把待處理字符串中所有符合 <pattern> 的模式全部替換為 <replacement> 字符串,而不是只替換第一個出現的模式。
s/<pattern>/<replacement>/e 表示將把 <replacemnet> 部分當作一個運算符,這個參數用的不多。

2 正則表達式中的常用模式
下面是正則表達式中的一些常用模式。

/pattern/  結果
. 匹配除換行符以外的所有字符
x? 匹配 0 次或一次 x 字符串
x* 匹配 0 次或多次 x 字符串,但匹配可能的最少次數
x+ 匹配 1 次或多次 x 字符串,但匹配可能的最少次數
.* 匹配 0 次或一次的任何字符
.+ 匹配 1 次或多次的任何字符
{m} 匹配剛好是 m 個 的指定字符串
{m,n} 匹配在 m個 以上 n個 以下 的指定字符串
{m,} 匹配 m個 以上 的指定字符串
[] 匹配符合 [] 內的字符
[^] 匹配不符合 [] 內的字符
[0-9] 匹配所有數字字符
[a-z] 匹配所有小寫字母字符
[^0-9] 匹配所有非數字字符
[^a-z] 匹配所有非小寫字母字符
^ 匹配字符開頭的字符
$ 匹配字符結尾的字符
\d 匹配一個數字的字符,和 [0-9] 語法一樣
\d+ 匹配多個數字字符串,和 [0-9]+ 語法一樣
\D 非數字,其他同 \d
\D+ 非數字,其他同 \d+
\w 英文字母或數字的字符串,和 [a-zA-Z0-9] 語法一樣
\w+ 和 [a-zA-Z0-9]+ 語法一樣
\W 非英文字母或數字的字符串,和 [^a-zA-Z0-9] 語法一樣
\W+ 和 [^a-zA-Z0-9]+ 語法一樣
\s 空格,和 [\n\t\r\f] 語法一樣
\s+ 和 [\n\t\r\f]+ 一樣
\S 非空格,和 [^\n\t\r\f] 語法一樣
\S+ 和 [^\n\t\r\f]+ 語法一樣
\b 匹配以英文字母,數字為邊界的字符串
\B 匹配不以英文字母,數值為邊界的字符串
a|b|c 匹配符合a字符 或是b字符 或是c字符 的字符串
abc 匹配含有 abc 的字符串
(pattern) () 這個符號會記住所找尋到的字符串,是一個很實用的語法。第一個 () 內所找到的字符串變成 $1 這個變量或是 \1 變量,第二個 () 內所找到的字符串變成 $2 這個變量或是 \2 變量,以此類推下去。
/pattern/i i 這個參數表示忽略英文大小寫,也就是在匹配字符串的時候,不考慮英文的大小寫問題。
\ 如果要在 pattern 模式中找尋一個特殊字符,如 “*",則要在這個字符前加上 \ 符號,這樣才會讓特殊字符失效
3、正則表達式的八大原則
如果在 Unix 中曾經使用過 sed、awk、grep 這些命令的話,相信對於正則表達式(Regular Expression)不會感到陌生。下面給大家介紹幾條正則表達式使用過程中的 8 大原則。

正則表達式在對付數據的戰鬥中可形成龐大的聯盟——這常常是一場戰爭。我們要記住下面八條原則:

· 原則1:正則表達式有三種不同形式(匹配(m/ /),替換(s/ / /eg)和轉換(tr/ / /))。

· 原則2:正則表達式僅對標量進行匹配( $scalar =~ m/a/; 可以工作; @array =~ m/a/ 將把@array作為標量對待,因此可能不會成功)。

· 原則3:正則表達式匹配一個給定模式的最早的可能匹配。缺省時,僅匹配或替換正則表達式一次( $a = ‘string string2’; $a =~ s/string/ /; 導致 $a = ‘string 2’)。

· 原則4:正則表達式能夠處理雙引號所能處理的任意和全部字符( $a =~ m/$varb/ 在匹配前把varb擴展為變量;如果 $varb = ‘a’ $a = ‘as’,$a =~ s/$varb/ /; 等價於 $a =~ s/a/ /; ,執行結果使 $a = " s" )。

· 原則5:正則表達式在求值過程中產生兩種情況:結果狀態和反向引用: $a=~ m/pattern/ 表示 $a 中是否有子串 pattern 出現,$a =~ s/(word1)(word2)/$2$1/ 則「調換」這兩個單詞。

· 原則6:正則表達式的核心能力在於通配符和多重匹配運算符以及它們如何操作。$a =~ m/\w+/ 匹配一個或多個單詞字符;$a =~ m/\d/" 匹配零個或多個數字。

· 原則7:如果欲匹配不止一個字符集合,Perl使用 “|" 來增加靈活性。如果輸入 m/(cat|dog)/ 則相當於「匹配字符串 cat 或者 dog。

· 原則8:Perl用 (?..) 語法給正則表達式提供擴展功能。

(想要學習所有這些原則?我建議大家先從簡單的開始,並且不斷的嘗試和實驗。

PHP MySQL Tips

Continuing from my earlier post on PHP performance, I thought I’d share a few Mysql tips that I’ve learnt over the years. Hope it helps someone and please leave a comment with your own tips or provide any corrections to the ones mentioned.

Word searching

1.

SELECT * FROM TABLE WHERE MATCH (`field`) AGAINST ('Keyword')

(Fastest)

2.

SELECT * FROM TABLE WHERE MATCH (`field`) AGAINST ('+Keyword' IN BOOLEAN MODE)

(Fast)

3.

SELECT * FROM TABLE WHERE RLIKE '(^| +)Keyword($| +)'

OR

SELECT * FROM TABLE WHERE
RLIKE '([[:space:]]|[[:<:]])Keyword([[:space:]]|[[:>:]])'

(Slow)

Contains searching

1.

SELECT * FROM TABLE WHERE MATCH (`field`) AGAINST ('Keyword*' IN BOOLEAN MODE)

(Fastest)

2.

SELECT * FROM TABLE WHERE FIELD LIKE 'Keyword%'

(Fast)

3.

SELECT * FROM TABLE WHERE MATCH (`field`) AGAINST ('*Keyword*' IN BOOLEAN MODE)

(Slow)

4.

SELECT * FROM TABLE WHERE FIELD LIKE '%Keyword%'

(Slow)

Recordsets

1.

SELECT SQL_CALC_FOUND_ROWS * FROM TABLE WHERE Condition LIMIT 0, 10

SELECT FOUND_ROWS()

(Fastest)

2.

SELECT * FROM TABLE WHERE Condition LIMIT 0, 10

SELECT COUNT(PrimaryKey) FROM TABLE WHERE Condition

(Fast)

3.

$result = mysql_query("SELECT * FROM table", $link);
$num_rows = mysql_num_rows($result);

(Very slow)

Joins

Use an INNER JOIN when you want the joining table to only have matching records that you specify in the join. Use LEFT JOIN when it doesn’t matter if the records contain matching records or not.

SELECT * FROM products
INNER JOIN suppliers ON suppliers.SupplierID = products.SupplierID

Returns all products with a matching supplier.

SELECT * FROM products
LEFT JOIN suppliers ON suppliers.SupplierID = products.SupplierID

WHERE suppliers.SupplierID IS NULL

Returns all products without a matching supplier.

Best practice

1. Always use lowercase for table names. (If you use different OS’s this is a must)
2. Always prepend the table name to the field. E.g. ProductName, SupplierPostCode.
This makes multiple joins very easy.
3. Always create a primary id field with the name of the table followed by the id. e.g. ProductID
4. Index fields used for joins.
5. Use a separate logging table or transactions for logs of table updates, deletes etc.

IE中打開UTF-8編碼title為中文的網頁會顯示空白頁的問題

(忘了引用來源)

很久很久以前(大概2005年10月 ~2006年3月),當時在blogger.com寫Blog。當時blogger.com有中文界面,對中文用戶也算是比較關心了,不過 blogger.com的所有模版裡都有一個問題,那就是<title>標籤被放在<meta>標籤前面。當title為中文的 時(比如Blog名為中文或者文章標題為中文),在IE下會出現顯示空白頁的問題。昨天Dre·J在群裡又問到這個問題,今天過來好好研究一下。

這個問題只存在於blogger.com中,WordPress系統中不存在。先說一下在blogger.com中這個問題的解決辦法:在模版的<body>標籤下面找到<title>標籤,調整成這樣:

<$BlogMetaData$>
<title><$BlogPageTitle$></title>

保證meta在前面就可以了。可以參考《感謝Yskin》《UTF-8字符集網頁在IE上會顯示空白問題的解決方案》

這個問題要從瀏覽器解析html的方式講起。瀏覽器讀取了頁面的html代碼後開始進行解析。解析前瀏覽器要先知道頁面的編碼方式,然後根據編碼方 式進行解碼,然後才能開始解析。我大概想了一下,瀏覽器可以從下面3個方面得到頁面編碼方式:HTTP Header中的"Content-Type"項、返回的html代碼開頭是否有BOM、html代碼中的meta標籤。

做了一個小測試,使用Windows 2000 SP4操作系統,IE6 SP1和Firefox 1.5.0.5瀏覽器。所有文件使用DOS格式換行符。測試代碼如下:

<?php
header("Content-Type: text/html; charset=utf-8");
?><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>你好啊</title>
</head>
<body>
你好啊。
</body>

先 不要前面的PHP語句,直接使用html文件,分無meta、meta在title前、meta在title後3種方式,分別做成GBK、UTF -8(no BOM)、UTF-8(BOM)三種編碼方式的文件,再分別用IE和Firefox測試。我的Blog所在的服務器上,訪問html文件時HTTP Header裡Content-Type是Content-Type: text/html。第二遍測試加上PHP語句,用Header函數給HTTP Header中加上Content-Type: text/html; charset=utf-8,再把第一遍做的重新做一遍。
IE6 SP1 Firefox 1.5.0.5 字節 地址 無meta meta在前 meta在後 —加了Header語句後— 無meta meta在前 meta在後

GBK 正常 正常 73 t11.html
UTF-8(no BOM) 空白頁 使用GBK解碼形成亂碼 80 t12.html
UTF-8(BOM) 正常 正常 83 t13.html
GBK 使用UTF-8解碼形成亂碼 使用UTF-8解碼形成亂碼 144 t21.html
UTF-8(no BOM) 正常 正常 151 t22.html
UTF-8(BOM) 正常 正常 154 t23.html
GBK 使用UTF-8解碼形成亂碼 使用UTF-8解碼形成亂碼 144 t31.html
UTF-8(no BOM) 空白頁 正常 151 t32.html
UTF-8(BOM) 正常 正常 154 t33.html
GBK 使用UTF-8解碼形成亂碼 使用UTF-8解碼形成亂碼 133 t11.php
UTF-8(no BOM) 正常 正常 140 t12.php
UTF-8(BOM) 正常 正常 143 t13.php
GBK 使用UTF-8解碼形成亂碼 使用UTF-8解碼形成亂碼 204 t21.php
UTF-8(no BOM) 正常 正常 211 t22.php
UTF-8(BOM) 正常 正常 214 t23.php
GBK 使用UTF-8解碼形成亂碼 使用UTF-8解碼形成亂碼 204 t31.php
UTF-8(no BOM) 正常 正常 211 t32.php
UTF-8(BOM) 正常 正常 214 t33.php

文件中有6個漢字和一個漢字句號,所以UTF-8(no BOM)格式比GBK格式多出7個字節。UTF-8的BOM佔用3個字節,所以UTF-8(BOM)比UTF-8(no BOM)多出3個字節。經驗證,所有數據都符合這個規則,所以各文件格式沒有錯誤。

PHP不支持BOM,又因為BOM的3個字符在最前面,顯示不包含在<?php…?>標籤裡,所以PHP引擎會3個字符輸出,於是 輸出的html文件也有了BOM。所以這次測試中,為了修改http header而加入的PHP語句不影響最終輸出的html文件的BOM。

從測試結果可以看出,瀏覽器(無論是IE還是Firefox)在解析頁面時,首先取HTTP Header中的Content-Type項,如果有寫明charset的話就認定頁面的編碼方式為charset指定的值。如果沒有指明,則認定為默認 值。根據上表,IE中文版的默認值是GB2312,Firefox中文版的默認值是GBK,不過IE的GB2312好像和GBK沒啥區別。然後,瀏覽器會 看一下有沒有BOM。一旦發現有UTF-8的3字節BOM,則重新認定頁面的編碼方式為UTF-8。

然後是解碼階段,解碼完成後是解析html的階段。解析html的過程中,當解析到head部分的meta標籤時,瀏覽器會根據<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />這個語句中的說明,重新認定編碼方式為charset後面的方式,中斷html解析過程,返回到解碼步驟重新解碼。

知道了這個步驟,再來看這個表:在加了Header語句設置了HTTP Header後,兩個瀏覽器解析所有頁面都是用的UTF-8方式,包括GBK編碼的頁面。(當然要正常解析GBK編碼的文件,可以在title前加上個 meta標籤標明編碼方式。)在上表的下半部分可以清楚的看到這一點。再來看上半部分,在沒有加Header語句的頁面裡,首先瀏覽器認定頁面編碼方式為 默認值GBK。檢測有無UTF-8的3字節BOM,檢測到的,認定頁面編碼方式為UTF-8,解碼再解析html,一切正常。如上表所示,上半部分帶 BOM的頁面都能正常顯示。如果沒有BOM,頁面可能是GBK或者UTF-8(no BOM)格式,瀏覽器會先按照默認的GBK方式開始解碼。頁面為GBK格式時,無meta時正常,有meta時瀏覽器解析到meta標籤會回頭重現按 UTF-8方式解碼,所以GBK,meta在前或後,無論IE還是FF都是亂碼。再看UTF-8(no BOM)的頁面,無meta時FF用GBK方式解碼下去,最終顯示亂碼,IE則解碼出錯,形成空白頁。有meta時,Firefox找到meta後回頭重 新按UTF-8方式解碼,所以無論meta在前或在後都是正常;IE則是在meta在前時能夠和Firefox一樣回頭重新解碼,當meta在後時,又是 解析到title出錯,返回空白頁。

所以,IE顯示空白頁的問題,很明顯是因為IE的解碼程序兼容性差。上網查了下,GBK的編碼範圍是0×8140-0xfefe。從GB2312- 80開始,因為ASCII碼的範圍是0~127,首字位是0,所以GB2312-80使用雙字節,並設置首字位為1。「GBK 亦採用雙字節表示,總體編碼範圍為 8140-FEFE,首字節在 81-FE 之間,尾字節在 40-FE 之間。」[via]UTF-8中中文都是3個字節的,由於Unicode中中日韓的文字都混在一起,可以使用Windows自帶的字符映射表查看CJK表意字符的範圍,即為漢字的範圍。(可以參考我的這篇文章裡的圖片)3字節的UTF-8編碼是這樣子的:1110xxxx 10xxxxxx 10xxxxxx,編碼範圍是8000-EFFF,首字節在80-EF之間,尾字節在00-FF之間。[via] 顯然當一段UTF-8編碼的文本被按照GBK方式解碼的時候,由於有一些編碼在GBK中不存在,造成解碼程序出現錯誤。當UTF-8文本被按照GBK的方 式解碼的時候,前兩個字節會被認為是一個字,後一個字節將和下一個字符結合。當<title>標籤裡的漢字數是偶數個時,勉強有3/4的概率 通過解碼程序(因為GBK的第二個字節要求是40-FE),當有奇數個漢字的時候,最後一個漢字的三個字節的最後一個字節會和< /title>的第一個字符<結合,而<的編碼是3C,正好不在尾字節40-FE的範圍中,造成錯誤。如果< /title>標籤前有多餘的空格也會產生錯誤,因為空格的編碼20也不在範圍中。

再做一個測試,修改t12.html中title的部分,修改成兩個漢字,再用IE打開發現不再是空白頁,而是用GBK編碼導致的亂碼頁面了。地址:s.html

所以,空白頁的出現是不固定的。《UTF-8字符集網頁在IE上會顯示空白問題的解決方案》所說的「IE 解析網頁編碼時是 HTML 內的標識優先的,然後是 HTTP header ;而mozilla 系列的瀏覽器剛剛好相反。」是不對的。在網上搜索「meta的作用」,很容易就可以找到一堆meta標籤的說明。比如《HTML中meta的作用》裡 提到:「meta是用來在HTML文檔中模擬HTTP協議的響應頭報文。」在meta標籤中寫和在HTTP頭裡寫是一樣的,這也是為瞭解決用普通HTML 寫網頁的人無法自行定義HTTP頭的問題。但是,meta是一個html標籤,所以必須進入到html解析的步驟才能生效,而生效後,瀏覽器會退回幾步, 重新設置好HTTP頭從頭再開始解碼、解析html。所以meta中寫的內容會覆蓋HTTP頭裡的內容,無論哪個瀏覽器都是這樣的。如果像他所說的, mozilla系列瀏覽器是HTTP Header優先於HTML內的標識,那meta標籤不就等於沒有用了嗎?這不符合html標準。

《一個 utf-8 網頁在 IE6 下的BUG》中 所說的出現空白頁必須的3項條件(1.title標籤裡的內容為中文其他雙字節字符;2.指定網頁編碼的 meta 信息在 title 標籤的下方;3.另存或轉換utf-8編碼時沒有包括 unicode 簽名 (BOM))基本上正確,不過不夠全面,具體的原因我上面已經詳細分析過了。還有BOM不能算簽名吧,唉,就叫他BOM好了,Byte Order Mark,字節序標識,用於UTF-16編碼的文件,在UTF-8編碼的文件中不需要標識字節序,所以被用來標識這是一個UTF-8編碼文件。

這個問題還是IE的兼容性問題,在解碼的時候如果遇到錯誤的編碼就中斷解碼。畢竟html代碼是從網絡上傳輸過來的,很可能傳錯幾個字節,所以解碼 程序不必弄的這麼嚴格吧。亂碼頁面起碼讓瀏覽者知道網頁已經打開,有點經驗的會知道切換網頁編碼,如果是空白頁很可能被瀏覽者認為是網頁本身就是空白的, 從而放棄瀏覽。IE在html解析和CSS解析上容錯性很好的呀,怎麼解碼這塊會做的這麼嚴格呢。某些天天喊叫IE兼容性好,IE能正常瀏覽的網頁多的 人,你看這個,這個,嘿嘿。

測試了一下,blogspot,sitesled,Blogger Spaces上的頁面都是返回的Content-Type: text/html,所以他們都會出現空白頁的問題。好像Apache默認情況下不會亂聲明編碼方式的,無論是國外的主機還是國內的主機。我的Blog的頁面的HTTP Header都包含Content-Type: text/html; charset=UTF-8, 後台的頁面也都有,一般不會有問題。比較奇怪的是,我查了WordPress和K2所有的文件,也沒發現哪兒用Header命令設置過這個HTTP頭。一 些輸出RSS和atom或者是發送trackback的文件都很仔細的用Header命令設置這個HTTP頭,不過不存在一個地方用了Header命令從 而一勞永逸地使所有輸出的頁面都包含這個頭的。難道Apache在處理PHP文件的時候會自動檢測文件的編碼方式並設置HTTP頭嗎?WordPress 自帶的WordPress Default和WordPress Classic模版都把單獨放在title標籤的前面,可能WordPress開發組注意到了這個問題,K2模版則沒有注意這個問題。blogger.com的模版也沒有注意這個問題,難道老外都習慣了meta一起放在title下面?

另外,這個是IE的bug,不過也不要認為你用的是MyIE、MyIE2、遨遊Maxthon、GreenBrowser、騰訊TT就不會受到影響,他們都是以IE為核心的,IE的bug他們一個個都跑不掉。儘早投降吧,投到Firefox或者Opera的懷抱裡來吧。

注音 漢語拼音 preg_split 正規劃切割

$Hupinyin = array(
‘ㄅ’=>’b’,’ㄆ’=>’p’,’ㄇ’=>’m’,’ㄈ’=>’f’
,’ㄉ’=>’d’,’ㄊ’=>’t’,’ㄋ’=>’n’,’ㄌ’=>’l’
,’ㄍ’=>’g’,’ㄎ’=>’k’,’ㄏ’=>’h’
,’ㄐ’=>’j’,’ㄑ’=>’q’,’ㄒ’=>’x’
,’ㄓ’=>’zh’,’ㄔ’=>’ch’,’ㄕ’=>’sh’,’ㄖ’=>’r’
,’ㄗ’=>’z’,’ㄘ’=>’c’,’ㄙ’=>’s’
,’ㄚ’=>’a’,’ㄛ’=>’o’,’ㄜ’=>’e’,’ㄝ’=>’e’
,’ㄞ’=>’ai’,’ㄟ’=>’ei’,’ㄠ’=>’ao’,’ㄡ’=>’ou’
,’ㄢ’=>’an’,’ㄣ’=>’en’,’ㄤ’=>’ang’,’ㄥ’=>’eng’
,’ㄦ’=>’er’
,’ㄧ’=>’i’,’ㄨ’=>’u’,’ㄩ’=>’u’
);
$word = “ㄢ";
foreach ($Hupinyin as $k => $v) {
if ($k == $word){
echo “$word = $v <br />\n";
}
}

$a=’000000000000023,886-0223584312,,300,8,2001,1,2,2,20061012164304,20061012164820;<br>000000000000023,886-0233221018,,300,8,2001,1,2,2,20061012164304,20061012164740′;
$a=preg_replace(“/(;<br>)/", ‘,’, $a);
$chars = preg_split(“/,/", $a,-1,PREG_SPLIT_DELIM_CAPTURE);
print_r($chars);

利用imagemagick來作縮圖

<?php
$w="240″; //自行設定的縮圖寬度
$h="320″; //自行設定的縮圖高度
if($_FILES[‘file’][‘type’]=="image/pjpeg" || $_FILES[‘file’][‘type’]=="image/gif" || $_FILES[‘file’][‘type’]=="image/png") {
if($_FILES[‘file’][‘type’]=="image/pjpeg") {
$filename=substr(rand(0,999999999999),1,7).".gif"; //隨機取檔名..我的習慣啦 ^^||
}
if($_FILES[‘file’][‘type’]=="image/gif") {
$filename=substr(rand(0,999999999999),1,7).".gif";
}
if($_FILES[‘file’][‘type’]=="image/png") {
$filename=substr(rand(0,999999999999),1,7).".png";
}
$size=$w."x".$h;
copy($_FILES[‘file’][‘tmp_name’],"/home/caisse/case/kf/data/file/b".$filename); //將暫存檔copy至自己定義的目錄..因為小弟大小圖都想要 ^^
$big_image="/home/caisse/case/kf/data/file/b".$filename;
$small_image="/home/caisse/case/kf/data/file/s".$filename;
$exec_str="/usr/bin/convert ‘-geometry’ “.$size." “.$big_image." “.$small_image; //注意"跟’唷
exec($exec_str);
} else {
echo “請上傳圖片";
}
?>
<form action="#" method="post" enctype="multipart/form-data" name="form1″>
<input type="file" name="file">
<input type="submit" name="Submit" value="送出">
</form>
<?php if($_FILES) { ?>
原始圖 <img src="/data/file/b<?php echo $filename; ?>"> <br>
裁切後的圖 <img src="/data/file/s<?php echo $filename; ?>">
<?php } ?>

亂數取碼當成驗證碼的問題

//此副程式的功能在於生成驗證碼圖片

//重設亂數種子
srand((double)microtime()*1000000);
//產生一組6位數的數字
$abc=substr(md5(uniqid(rand())),mt_rand(0,15),6);

//建立一個 80*30 畫素的圖形
$img = imagecreate(80,30);

//設定顏色
$white = imagecolorallocate($img,255,255,255);//設定背景顏色為白色
$gray = ImageColorAllocate($img,150,150,150);//設定顏色為灰色

//產生底色
imagefill($img,60,28,$gray);

//將四位元整數驗證碼繪入圖片
imagestring($img,5,10,8,$abc,$white);

for($i=0;$i<50;$i++)//加入干擾像素
{
imagesetpixel($img,rand()%70,rand()%30,$white);
}

header(“Content-type:image/png");
ImagePNG($img);

ImageDestroy($img);
?>