前一陣子去參加OSSF的Annotation講座
裡面有提到JUnit4作單元測試
下面一個參考網站
http://liyiye.javaeye.com/blog/443239
以往作單元測試的時候都必須去繼承TestCase類別
這無疑阻礙了測試程式的設計,但是使用Annotation為基礎作Unit test的話
不只函式名稱不用被綁死,在設計上也更簡單
2009年12月17日 星期四
2009年12月14日 星期一
[Java]Java呼叫C/C++ DLL
接續上一篇,這一陣子要寫可以動態連結的程式,其實我最先開始想到的就是用windows的DLL(Dynamic-link library )或是Linux的SO(Shared Object)
一來這樣速度快二來這樣子也有個更新的彈性,只是這樣一來可能就無法實現跨平台的優點。
在Java有提供JNI來實驗呼叫c\c++的dll功能
放幾個我參考的網站
一般來說會先寫個.java檔去產生Header。假設今天我一隻程式叫Hello.java
那我可以寫一個批次檔(.bat)去幫我產生要用的header
makeHeader.bat
其中javah這個指令就是用來產生JNI Header,之後產生一個標頭檔叫Hello.h
寫一個.c或是.cpp去實作他產生DLL之後就可以給Java呼叫
不過老實說這樣很不方便,萬一Hello.java要增加新函式就會變得很不方便
因此我會比較建議用JNA+CDT的方式去做,如果要用Windows+Eclipse去開發C++的話,有兩個套件要先裝起來,一個是MinGW,另一個則是CDT
一來這樣速度快二來這樣子也有個更新的彈性,只是這樣一來可能就無法實現跨平台的優點。
在Java有提供JNI來實驗呼叫c\c++的dll功能
放幾個我參考的網站
- http://blog.ring.idv.tw/comment.ser?i=127
- http://www.blogjava.net/orangewhy/archive/2007/05/24/119645.html
- http://enijmax.2y.idv.tw/linux/CLib_Jni.html
- http://topatis.blog.ithome.com.tw/post/613/17245
- http://mqjing.blogspot.com/2009/04/c-gcc-library.html
一般來說會先寫個.java檔去產生Header。假設今天我一隻程式叫Hello.java
那我可以寫一個批次檔(.bat)去幫我產生要用的header
makeHeader.bat
javac Hello.java
javah -jni Hello
@pause
其中javah這個指令就是用來產生JNI Header,之後產生一個標頭檔叫Hello.h
寫一個.c或是.cpp去實作他產生DLL之後就可以給Java呼叫
不過老實說這樣很不方便,萬一Hello.java要增加新函式就會變得很不方便
因此我會比較建議用JNA+CDT的方式去做,如果要用Windows+Eclipse去開發C++的話,有兩個套件要先裝起來,一個是MinGW,另一個則是CDT
[Java]URLClassLoader運用上的一點筆記
這一陣子接了一個case必須要撈一些網站的資料
由於這是必須多人maintain 的一個系統,要防止對方網頁改版而撈不到資料
因此我想到了Java的dynamic binding功能
在Java原生支援dynamic binding,而他主要又分成Implicit(隱式)跟explicit(顯式)兩大類
參考資料:http://www.yuloo.com/news/2008-08-27/112873.html
由於這是必須多人maintain 的一個系統,要防止對方網頁改版而撈不到資料
因此我想到了Java的dynamic binding功能
在Java原生支援dynamic binding,而他主要又分成Implicit(隱式)跟explicit(顯式)兩大類
參考資料:http://www.yuloo.com/news/2008-08-27/112873.html
2009年11月3日 星期二
PHP:mail函式 標題出現亂碼問題
今天受託替人寫自動回信的功能
因為功能很小,所以我很自然使用mail()函式去做
但是卻出現了標題有全形符號變成亂碼的問題,像是『』,≠ 等等
後來找的一些資料
http://blog.roodo.com/rocksaying/archives/2998451.html
http://blog.roodo.com/rocksaying/archives/2950655.html
原來這問題存在已久了,mail()函式之下還有個mb_send_mail()函式,mail()函式裡面會用到mb_send_mail()進行傳信的動作,所以我只要將原先的寄信程式
修改成用mb_send_mail()的方式去自定編碼寄送就可以解決問題
不過這種函式處裡太底層了點,所以還是用別人寫好的套件像是PHPMailer來進行工作或許會是比較好的選擇
因為功能很小,所以我很自然使用mail()函式去做
但是卻出現了標題有全形符號變成亂碼的問題,像是『』,≠ 等等
後來找的一些資料
http://blog.roodo.com/rocksaying/archives/2998451.html
http://blog.roodo.com/rocksaying/archives/2950655.html
原來這問題存在已久了,mail()函式之下還有個mb_send_mail()函式,mail()函式裡面會用到mb_send_mail()進行傳信的動作,所以我只要將原先的寄信程式
mail("del680202@gmail.com",$title,$count,$option);
修改成用mb_send_mail()的方式去自定編碼寄送就可以解決問題
mb_internal_encoding("UTF-8"); \\定義編碼方式
mb_send_mail("del680202@gmail.com",$title,$count,$option);
不過這種函式處裡太底層了點,所以還是用別人寫好的套件像是PHPMailer來進行工作或許會是比較好的選擇
Goolge 學術搜尋 導入BibTeX 功能
今天再找paper的時候突然的發現Google有提供導入BibTeX的功能
平常我們在寫reference的時候都必須去找那篇paper的出處來作成Bibtex
有了這個功能的話可以省下不少時間
平常我們在寫reference的時候都必須去找那篇paper的出處來作成Bibtex
有了這個功能的話可以省下不少時間
首先進入學術搜尋後,點選旁邊的[學術搜尋偏好],之後到[文獻管理軟体]那一項
選擇[的鏈接] ,之後搜尋的結果就可以看到[導入BibTeX]
點進去之後就能看到我們寫論文要用的BibText,或許格式不會符合Lab要求,但是可以減少我們找資料的時間
2009年9月28日 星期一
undefined reference to `pow'
今天重灌了ubuntu
想要寫些程式的時候出現了下面的錯誤訊息
也不只這個,凡是跟數學函式相關的使用就會出現這類錯誤
像是undefined reference to `sqrt'等等
但是我有確實的include <math.h>,卻仍然找不到
而後來google了一下,發現可以從gcc下手解決
我把原來的
加上-lm 如下
就成功解決這個問題
再找這問題的時候額外的一個問題
這是因為從新安裝的時候沒有安裝包含lib的套件
所以只要輸入下面指令安裝就可以解決
想要寫些程式的時候出現了下面的錯誤訊息
undefined reference to `pow'
也不只這個,凡是跟數學函式相關的使用就會出現這類錯誤
像是undefined reference to `sqrt'等等
但是我有確實的include <math.h>,卻仍然找不到
而後來google了一下,發現可以從gcc下手解決
我把原來的
gcc -o xxx xxx.c
加上-lm 如下
gcc -lm -o xxx xxx.c
就成功解決這個問題
再找這問題的時候額外的一個問題
警告: 隱含宣告與內建函式 「printf」 不相容
這是因為從新安裝的時候沒有安裝包含lib的套件
所以只要輸入下面指令安裝就可以解決
sudo apt-get install build-essential
標籤:
Linux,
Linux c/c++
2009年9月11日 星期五
無法存取 \\XXX 。您可能沒有使用這個網路資源的權限。請聯絡這個網路伺服器的系統管理員,了解您是否有存取權限。 登入失敗:使用者帳戶限制。可能原因為不允許空的密碼,登入時數限制,或強的原則限制。
今天幫學長處裡電腦問題
平常我們都使用\\IP或是\\SrverName或是從網路芳鄰去存取遠端電腦上的資源
但是今天出現的問題是我們這邊一堆電腦
每一台都能連到Server就是學長那台電腦不能
他存取的時候會出現
這樣的錯誤訊息(從別的地方copy來的,可能會有些不同)
平常我們都使用\\IP或是\\SrverName或是從網路芳鄰去存取遠端電腦上的資源
但是今天出現的問題是我們這邊一堆電腦
每一台都能連到Server就是學長那台電腦不能
他存取的時候會出現
無法存取 \\XXX 。您可能沒有使用這個網路資源的權限。請聯絡這個網路伺服器的系統管理員,了解您是否有存取權限。
登入失敗:使用者帳戶限制。可能原因為不允許空的密碼,登入時數限制,或強的原則限制。
這樣的錯誤訊息(從別的地方copy來的,可能會有些不同)
2009年9月10日 星期四
window中文網頁移植到Linux變成無法解讀
今天把一些網頁從windows上轉移到Linux上的時候
部分網頁發生變成亂碼的情況,後來看了一下
windows上的網頁都是big5編碼,而Linux上則是utf-8
但是這種情況我加上header
一點用都沒有
後來找了些資料,發現Linux上有轉碼的指令
透過這種編碼指令可以替我解決這種部分網頁編碼問題
參考資料
部分網頁發生變成亂碼的情況,後來看了一下
windows上的網頁都是big5編碼,而Linux上則是utf-8
但是這種情況我加上header
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
一點用都沒有
後來找了些資料,發現Linux上有轉碼的指令
iconv -f [fromcode ]-t [tocode] [file]
透過這種編碼指令可以替我解決這種部分網頁編碼問題
iconv -f big5 -t utf8 index.php > index_utf8.php
參考資料
2009年9月9日 星期三
Apache:You don't have permission to accesson this server.
今天幫別人用Linux建帳號的時候
須要每個user都有屬於自己專屬的www家目錄,很幸運的apache就有這種功能了
先去找apache的設定檔 /etc/httpd/conf/httpd.conf
去裡面尋找UserDir的設定值
一般來講預設都是public_html,也就是說只要user家目錄下有個public_html目錄
那就會是他的wwwroot目錄
一般來說都是要自己建,假設我有個帳號Tom
那user家目錄就是
我可以用mkdir去建我要的public_html
但是我要存取的時候出現了錯誤訊息
上網google一下資料,看到人家說要修改
參考資料
把deny改成allow,不過後來發現早就設定好了 所以上面那招並沒解決問題
後來想想應該是權限問題,但是用ls -al 查了一下,我public_html跟其下權限都已經是755了
後來去看了一下鳥哥的文章,原來是使用者家目錄本身也要設定成755
新建的user帳號的家目錄權限是drwx----- ,必須修改成drwx-xr-x才能讓apache存取該目錄
所以建public_html正確順序應該如下
root狀態
user狀態
須要每個user都有屬於自己專屬的www家目錄,很幸運的apache就有這種功能了
先去找apache的設定檔 /etc/httpd/conf/httpd.conf
去裡面尋找UserDir的設定值
<IfModule mod_userdir.c>
........
UserDir public_html
</IfModule >
一般來講預設都是public_html,也就是說只要user家目錄下有個public_html目錄
那就會是他的wwwroot目錄
一般來說都是要自己建,假設我有個帳號Tom
那user家目錄就是
/home/Tom
我可以用mkdir去建我要的public_html
mkdir /home/Tom/public_html
但是我要存取的時候出現了錯誤訊息
You don't have permission to accesson this server.
上網google一下資料,看到人家說要修改
<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
< /Directory >
參考資料
把deny改成allow,不過後來發現早就設定好了 所以上面那招並沒解決問題
後來想想應該是權限問題,但是用ls -al 查了一下,我public_html跟其下權限都已經是755了
後來去看了一下鳥哥的文章,原來是使用者家目錄本身也要設定成755
新建的user帳號的家目錄權限是drwx----- ,必須修改成drwx-xr-x才能讓apache存取該目錄
所以建public_html正確順序應該如下
root狀態
~]$ cd /home/Tom
~]$ mkdir public_html
~]$ chmod 755 public_html
~]$ chmod 755 /home/Tom
user狀態
~]$ cd ~
~]$ mkdir public_html
~]$ chmod 755 public_html
~]$ chmod 755 ~
2009年9月6日 星期日
ubuntu 9.04 PCMAN X 亂碼問題
Linux設定DNS
之前windows要設置DNS很容易
不過Linux下要設定要去修改文件/etc/resolv.conf
最簡單的設定
我在裝ubuntu 9.04的時候/etc找不到resolv.conf文件,到是有一個resolv.conf資料夾
不過要設置DNS還是一樣去設/etc/resolv.conf,自己創造一resolv.conf個就可以了
題外話,在玩Ubuntu 9.04的時候,桌面特效的menu不見了
要使用的話要再去安裝,安裝指令如下
之後就會出現compizconfig-settings-manager讓我們使用桌面特效了
參考資料
不過Linux下要設定要去修改文件/etc/resolv.conf
vi /etc/resolv.conf
最簡單的設定
nameserver xxx.xxx.xxx.xxx #第一個DNS Server位置
nameserver xxx.xxx.xxx.xxx #第二個DNS Server位置
我在裝ubuntu 9.04的時候/etc找不到resolv.conf文件,到是有一個resolv.conf資料夾
不過要設置DNS還是一樣去設/etc/resolv.conf,自己創造一resolv.conf個就可以了
題外話,在玩Ubuntu 9.04的時候,桌面特效的menu不見了
要使用的話要再去安裝,安裝指令如下
sudo apt-get install compizconfig-settings-manager
之後就會出現compizconfig-settings-manager讓我們使用桌面特效了
參考資料
vsftpd:530 This FTP server is anonymous only.
今天實驗室server重開的時候 FTP忽然登不進去了,沒辦法使用一般帳號登入 只能用匿名帳號登入
錯誤訊息如下
後來google了一下資料,要去修改/etc/vsftpd/vsftpd.conf
看到有說要增加
或是
以我的情況,我是屬於後者 我查了vsftpd.conf
local_enable被設置成NO(有的人是被#註解調)
local_enable要設置了才能讓機器上的實體帳號才能登入
可是設置之後卻還是不能登入,server也restart過了
後來在找了一下資料,我的vsftpd是被xinetd啟動的,xinetd的設置檔是放在/etc之下
所以我把/etc/vsftpd/vsftpd.conf整份複製到/etc/vsftpd.conf就可以了
但是啟動後出現另一個錯誤訊息
查了一下原因是因為port 21衝突,21 port被重複使用了
我之前用/etc/init.d/vsftpd去啟動了vsftpd,但是xinetd也啟動了vsftpd
關掉其中一個就好了,我是選擇關掉xinetd啟動那個
輸入
修改xinetd的vsftpd設定
把disable設定成yes,之後輸入
重新啟動服務就可以了
錯誤訊息如下
530 This FTP server is anonymous only.
後來google了一下資料,要去修改/etc/vsftpd/vsftpd.conf
看到有說要增加
pam_service_name=vsftpd
或是
local_enable=YES
以我的情況,我是屬於後者 我查了vsftpd.conf
local_enable被設置成NO(有的人是被#註解調)
local_enable要設置了才能讓機器上的實體帳號才能登入
可是設置之後卻還是不能登入,server也restart過了
後來在找了一下資料,我的vsftpd是被xinetd啟動的,xinetd的設置檔是放在/etc之下
所以我把/etc/vsftpd/vsftpd.conf整份複製到/etc/vsftpd.conf就可以了
cp /etc/vsftpd/vsftpd.conf /etc/vsftpd.conf
但是啟動後出現另一個錯誤訊息
500 OOPS: could not bind listening IPv4 socket
查了一下原因是因為port 21衝突,21 port被重複使用了
我之前用/etc/init.d/vsftpd去啟動了vsftpd,但是xinetd也啟動了vsftpd
關掉其中一個就好了,我是選擇關掉xinetd啟動那個
輸入
vi /etc/xinetd.d/vsftpd
修改xinetd的vsftpd設定
# default: on
# description:
# The vsftpd FTP server serves FTP connections. It uses
# normal, unencrypted usernames and passwords for authentication.
# vsftpd is designed to be secure.
service ftp
{
socket_type = stream
wait = no
user = root
server = /usr/local/sbin/vsftpd
# server_args =
# log_on_success += DURATION USERID
# log_on_failure += USERID
nice = 10
disable = yes
}
把disable設定成yes,之後輸入
/etc/init.d/xinetd restart
重新啟動服務就可以了
2009年8月31日 星期一
PHP呼叫父類別建構子
在Java的時候呼叫父類別方法是用super關鍵字
在C#則是使用base關鍵字
到了PHP必須使用另一個他預設的parent關鍵字
今天我想呼叫父類別建構式的話方法如下
在C#則是使用base關鍵字
到了PHP必須使用另一個他預設的parent關鍵字
今天我想呼叫父類別建構式的話方法如下
class Base{
var $db;
function __construct($db){
$this->db=$db;
}
}
class Child extends Base{
function __construct($db){
parent::__construct($db);/*呼叫父類別方法*/
}
}
2009年8月30日 星期日
float:left時,div區塊會穿透過去問題
今天再用css作layout的時候遇到的一些問題
想說用smarty寫個留言版給blog用,於是模擬了下列欄位
HTML
css碼
結果如下圖所示
class為item區塊他的border延伸到icon區塊,float:left效果只對文字作出反應
但是對於div原先的size並沒有做出相對的反應,所以他的邊界依然跟icon區塊重疊
後來想到用overflow:hidden來隱藏那不該顯示的區塊
結果如下
好極了,這次item區塊的邊界沒有透到icon區塊去
但是後來測試發現,這效果在IE6下沒有用(又是IE)
儘管IE7、8還有firefox都能正常顯示,但是還是得顧慮到IE6的用戶
後來發現把item的position屬性設置就能解決IE6的這個bug
最終css碼如下
想說用smarty寫個留言版給blog用,於是模擬了下列欄位
HTML
<div class="guestpost">
<div class="header"><!--{$curr->topic}--></div>
<div class="info">
<div class="icon"><!--{$curr->icon}--></div>
<div class="item"><!--{$curr->name}--></div>
<div class="item"><!--{$curr->email}--></div>
</div>
<div class="post"><!--{$curr->post}--></div>
<div class="floor"><!--{$curr->date}--></div>
</div>
css碼
.guestpost{ border:1px #C00 solid}
.guestpost .header{ border:1px #009 solid}
.guestpost .info .icon{ float:left; width:100px; height:100px; border:1px #009 solid;}
.guestpost .info .item{ border:1px #0a9 solid; }
.guestpost .post{ clear:both; border:1px #d09 solid; min-height:200px;}
.guestpost .floor{ text-align:right; border:1px #dd9 solid}
結果如下圖所示
class為item區塊他的border延伸到icon區塊,float:left效果只對文字作出反應
但是對於div原先的size並沒有做出相對的反應,所以他的邊界依然跟icon區塊重疊
後來想到用overflow:hidden來隱藏那不該顯示的區塊
.guestpost{ border:1px #C00 solid}
.guestpost .header{ border:1px #009 solid}
.guestpost .info .icon{ float:left; width:100px; height:100px; border:1px #009 solid;}
.guestpost .info .item{ border:1px #0a9 solid; overflow:hidden ; }
.guestpost .post{ clear:both; border:1px #d09 solid; min-height:200px;}
.guestpost .floor{ text-align:right; border:1px #dd9 solid}
結果如下
好極了,這次item區塊的邊界沒有透到icon區塊去
但是後來測試發現,這效果在IE6下沒有用(又是IE)
儘管IE7、8還有firefox都能正常顯示,但是還是得顧慮到IE6的用戶
後來發現把item的position屬性設置就能解決IE6的這個bug
最終css碼如下
.guestpost{ border:1px #C00 solid}
.guestpost .header{ border:1px #009 solid}
.guestpost .info .icon{ float:left; width:100px; height:100px; border:1px #009 solid;}
.guestpost .info .item{ border:1px #0a9 solid; overflow:hidden ; position:relative }
/*overflow:hidden一定要加 不然框線會向左突出到float:left的區塊 position:relative 針對IE6 設定了overflow才有效果 */
.guestpost .post{ clear:both; border:1px #d09 solid; min-height:200px;}
.guestpost .floor{ text-align:right; border:1px #dd9 solid}
PHP date函數時差八小時的解決方法
使用date函數取得的時間會跟系統時間相差八小時
他有兩個解決方法
他有兩個解決方法
- 在date函式之前加上
date_default_timezone_set(PRC);
- 修改PHP.ini的date.timezone 改成date.timezone=PRC
- 暴力法,自己修正那八小時
date(”Y-m-d H:i:s”, time()+8*60*60);
2009年8月27日 星期四
PHP include file 時使用dirname取得絕對路徑
今天想寫網站時候育到的一個問題
我include的file找不到檔案,但是我檢查了語法並無問題
我架構大改長下面這樣
MyProject資料夾底下有一個檔案(index.php)跟兩個資料夾(core,Model)
我index.php去include config.php
而 config.php又去include DBHelper.php
奇怪的是他竟然跟我說找不到DBHelper.php,看了一下路徑設置並沒有錯
後來找了一下資料require_once參考的路徑是"現在程式"所在路徑
所以我以為config.php會很自然往上一層到MyProject資料夾在到Model找DBHelper.php
但是由於我現在程式是MyProject資料夾之下的index.php,所以他變成先到MyProject的上一層資料夾在去Model資料夾找
但是這樣很麻煩阿,我很多程式都會include config.php藉著他去include DBHelper.php
有沒有辦法在不同資料夾下尋找呢?
後來想到了用程式去叫出config.php的絕對路徑,在以此路徑去尋找相對位置
之前有提過__FILE__可以幫我們找出檔案的絕對位置,他不會受include影響
儘管是index.php去include config.php,只要__FILE__是寫在config.php
他抓出來的就是config.php的絕對路徑
因此我將程式碼修改如下
如此一來,就能解決include時路徑不同的問題
我include的file找不到檔案,但是我檢查了語法並無問題
我架構大改長下面這樣
MyProject
-index.php
-core
|
-config.php
-Model
|
-DBHelper.php
MyProject資料夾底下有一個檔案(index.php)跟兩個資料夾(core,Model)
我index.php去include config.php
require_once 'core/config.php';
而 config.php又去include DBHelper.php
require_once '../Model/DBHelper.php';
奇怪的是他竟然跟我說找不到DBHelper.php,看了一下路徑設置並沒有錯
後來找了一下資料require_once參考的路徑是"現在程式"所在路徑
所以我以為config.php會很自然往上一層到MyProject資料夾在到Model找DBHelper.php
但是由於我現在程式是MyProject資料夾之下的index.php,所以他變成先到MyProject的上一層資料夾在去Model資料夾找
但是這樣很麻煩阿,我很多程式都會include config.php藉著他去include DBHelper.php
有沒有辦法在不同資料夾下尋找呢?
後來想到了用程式去叫出config.php的絕對路徑,在以此路徑去尋找相對位置
之前有提過__FILE__可以幫我們找出檔案的絕對位置,他不會受include影響
儘管是index.php去include config.php,只要__FILE__是寫在config.php
他抓出來的就是config.php的絕對路徑
因此我將程式碼修改如下
define("CONFIG_DIR",dirname(__FILE__));//抓出config.php的絕對path dir
require_once CONFIG_DIR.'../Model/DBHelper.php';//就像是/www/MyProject/core/../Model/DBHelper.php
如此一來,就能解決include時路徑不同的問題
2009年8月24日 星期一
PHP include file時轉碼
今天幫人寫網頁的時候,所遇到的一個小問題
平常都會習慣把網頁的像是header啦floor啦弄成template
再用include的方式include近來
但是當我想把big5碼的檔案include到utf-8的網頁
或者我想把utf-8的網頁include到big5的網頁就會出問題
用file_get_contents嘛,因為我習慣template加進html宣告標籤 又不合用
有沒有辦法把include進來的檔案從新編碼
後來找到了用output buffer的方式,先把include近來的檔案放進buffer而不輸出
再把output buffer的內容進行編碼,這樣就可以解決我遇到的問題了
範例如下
平常都會習慣把網頁的像是header啦floor啦弄成template
再用include的方式include近來
但是當我想把big5碼的檔案include到utf-8的網頁
或者我想把utf-8的網頁include到big5的網頁就會出問題
用file_get_contents嘛,因為我習慣template加進html宣告標籤 又不合用
有沒有辦法把include進來的檔案從新編碼
後來找到了用output buffer的方式,先把include近來的檔案放進buffer而不輸出
再把output buffer的內容進行編碼,這樣就可以解決我遇到的問題了
範例如下
ob_start();
include 'template/header.tpl';/*把include的file先不輸出到螢幕 放到緩衝*/
$table=ob_get_contents();/*從緩衝取得include內容*/
ob_end_clean(); /*關閉並結束緩衝*/
/*輸出*/
echo iconv("utf-8","big5",$table);
ob_flush();
flush();
2009年8月22日 星期六
javascript 取得網頁最後修改日期
這兩天幫別人做網站,有要求下方要標註修改日期
手動修改太麻煩了,找找javascript有沒有方法
後來找到javascript可以用document.lastModified取得文見最後修改日期
如果lastModified提供的格式不符合需求的話
也可以用內建的Date物件重新包裝
舉個例子
手動修改太麻煩了,找找javascript有沒有方法
後來找到javascript可以用document.lastModified取得文見最後修改日期
如果lastModified提供的格式不符合需求的話
也可以用內建的Date物件重新包裝
舉個例子
var lastModDate = new Date(document.lastModified);
document.write("最後修改日期:" +lastModDate.toDateString());
PHP 的__XXX
PHP有些是前面帶有兩個底線 '__'所組成的預設函式或變數
因為我比較不喜歡季這些有特別涵義的東西,簡單做個筆記把他記下來
這是個供類別使用的函式,就如同字面上意義,他可以代表類別建構式
一般沒寫這個函式的時候,PHP會去尋找同名的functoin當建構式
儘管大小寫不同,舉個例子
但是如果有寫__construct的話,則會優先使用__construct,而原先同名的function則可以當member function使用
物件解構式,物件銷毀時要做的事情
PHP的setter跟getter function,當object使用->去取值或用->=去設值的時候會呼叫的函式
儘管那個member從未定義一樣會去呼叫,__get須要一個參數,而__set則須要兩個參數
假設我用$p->Data,就像呼叫$p->__get("Data");
而如果我使用$p->Data="Tom"; 就像呼叫$p->__set("Data","Tom");
這樣的好處是能夠把一些變數資訊隱藏起來
User不須要知道我變數是如何操作,昨天在透視 WebMVC看到的一個蠻妙的作法,跟關連陣列結合使用
這個函式可以讓物件配合echo像一般變數一樣輸出,他必須有個return值
作overloading時可以用到,雖然一般都選擇預設參數的方式,這個我就不常用了
__call會傳進兩個參數,一個function name一個參數陣列
我使用$p->fun(1,2,3)就好像在呼叫$p->__call("fun",array(1,2,3))
他的好處,是function名稱不再受到綁定,參數也可以隨意
而fun必須是一個class未定意的function,如果有定義會採用以定義的
下面舉兩個例子,使用預設參數跟使用__call
其他一些__clone、__iset、__unset也大概都差不多用法,不過使用機率不大就是了,有興趣在去查手冊
上面的__XXX都必須在class裡面,而這個__autoload則是個獨立function,當呼叫一個不存在的class的時候
他會就會呼叫__autoload去試圖將他載入,他會傳入一個參數,也就是呼叫的class name
當我用$p=new People();,假設People不存在現有類別,他就會去呼叫__autoload("People");
假設我把上面範例拆開
也有人會把一個class一個php檔並設成同樣的名稱,這樣就可以把load動作簡化,這個在客制Lib的時候很好用
其他還有一些是__開頭的變數
我比較常用到的只有__FILE__,可以取得程式檔案的絕對位置
像是c:\appser\www\xxx.php,可以配合dirname取得檔案目前目錄
像是dirname(__FILE__)可以得到c:\appser\www\
-------------------------------------
題外話,在看透視 WebMVC(這篇文章很推薦)的時候,看到了一個很有趣的用法
就是把變數字串弄成函式或是另一個變數
而這個應用也可以用在class上
因為我比較不喜歡季這些有特別涵義的東西,簡單做個筆記把他記下來
__construct
這是個供類別使用的函式,就如同字面上意義,他可以代表類別建構式
一般沒寫這個函式的時候,PHP會去尋找同名的functoin當建構式
儘管大小寫不同,舉個例子
class People{
function people(){
echo 'people';
}
}
$p=new People();
//output:
people
但是如果有寫__construct的話,則會優先使用__construct,而原先同名的function則可以當member function使用
class People{
function __construct(){
echo 'construct';
}
function people(){
echo 'people';
}
}
$p=new People();// call __construct()
$p->people();//call member function people()
//output:
construct
people
__destruct
物件解構式,物件銷毀時要做的事情
class People{
function __destruct(){
//TODO
}
}
__get,__set
PHP的setter跟getter function,當object使用->去取值或用->=去設值的時候會呼叫的函式
儘管那個member從未定義一樣會去呼叫,__get須要一個參數,而__set則須要兩個參數
假設我用$p->Data,就像呼叫$p->__get("Data");
而如果我使用$p->Data="Tom"; 就像呼叫$p->__set("Data","Tom");
class People{
function __get($name){
echo "get function para: $name";
}
function __set($name,$value)
{
echo "set function para: name=$name,value=$value";
}
}
$p=new People();
$p->iget;//呼叫 __get($name) 並將iget當參數傳入
$p->iset=100;//呼叫 __set($name,$value) 並將iset跟100當參數傳入
//output:
get function para: iget
set function para: name=iset,value=100
這樣的好處是能夠把一些變數資訊隱藏起來
User不須要知道我變數是如何操作,昨天在透視 WebMVC看到的一個蠻妙的作法,跟關連陣列結合使用
class People{
var $arr=array();//一個空陣列
function __get($name){
echo "get function para: $name ";
return (isset($this->arr[$name]))?$this->arr[$name]:" no \$arr[$name]";
}
function __set($name,$value)
{
echo "set function para: name=$name,value=$value ";
$this->arr[$name]=$value;
}
}
$p=new People();
echo "get:".$p->iget;
$p->iset=100;
echo "get:".$p->iset;
//output
get function para: iget
get: no $arr[iget]
set function para: name=iset,value=100
get function para: iset
get:100
__toString
這個函式可以讓物件配合echo像一般變數一樣輸出,他必須有個return值
class People{
function __toString(){
return "I am a people";
}
}
$p=new People();
echo $p;
//output
I am a people
__call
作overloading時可以用到,雖然一般都選擇預設參數的方式,這個我就不常用了
__call會傳進兩個參數,一個function name一個參數陣列
我使用$p->fun(1,2,3)就好像在呼叫$p->__call("fun",array(1,2,3))
他的好處,是function名稱不再受到綁定,參數也可以隨意
而fun必須是一個class未定意的function,如果有定義會採用以定義的
下面舉兩個例子,使用預設參數跟使用__call
class People{
function operation($a="abc",$b=123){
echo "default:"."$a : $b";
}
function __call($name,$args)
{
echo "call function $name args:";
if(isset($args))
foreach ($args as $arg)
{
echo "$arg ,";
}
}
}
$p=new People();
//default
$p->operation();
$p->operation(99);
$p->operation(99,234);
//__call
$p->call();
$p->call(1);
$p->call(1,"Tom");
$p->bye(1,2,3,4);
//output
default:abc : 123
default:99 : 123
default:99 : 234
call function call args:
call function call args:1 ,
call function call args:1 ,Tom ,
call function bye args:1 ,2 ,3 ,4 ,
其他一些__clone、__iset、__unset也大概都差不多用法,不過使用機率不大就是了,有興趣在去查手冊
__autoload
上面的__XXX都必須在class裡面,而這個__autoload則是個獨立function,當呼叫一個不存在的class的時候
他會就會呼叫__autoload去試圖將他載入,他會傳入一個參數,也就是呼叫的class name
當我用$p=new People();,假設People不存在現有類別,他就會去呼叫__autoload("People");
假設我把上面範例拆開
//strFunctionClass.php
class People{
}
//strFunction.php
function __autoload($class){
if($class=="People")
{
include_once 'strFunctionClass.php';
}
echo "call Class :$class";
}
$p=new People();
//output
call Class :People
也有人會把一個class一個php檔並設成同樣的名稱,這樣就可以把load動作簡化,這個在客制Lib的時候很好用
//People.php
class People{...}
//index.php
function __autoload($class){
include_once "$class.php";
}
$p=new People();
其他還有一些是__開頭的變數
echo nl2br("\n").__METHOD__;/*Class的方法名稱*/
echo nl2br("\n").__FILE__;/*檔案所在絕對位置*/
echo nl2br("\n").__CLASS__;/*Class 名稱 在Class內才有用*/
echo nl2br("\n").__FUNCTION__;/*Function 名稱 在function內才有用*/
echo nl2br("\n").__LINE__;/*程式碼所在行數*/
我比較常用到的只有__FILE__,可以取得程式檔案的絕對位置
像是c:\appser\www\xxx.php,可以配合dirname取得檔案目前目錄
像是dirname(__FILE__)可以得到c:\appser\www\
-------------------------------------
題外話,在看透視 WebMVC(這篇文章很推薦)的時候,看到了一個很有趣的用法
就是把變數字串弄成函式或是另一個變數
function fun(){}
$temp=9999;
$var="temp";
echo $$var;//output 9999 就像 echo $temp
$temp="fun";
$temp();//最後會變成fun();
而這個應用也可以用在class上
class Action{
var $_action;
function setAction($action)
{
$this->_action=$action;
}
function run(){
if(method_exists($this,$this->_action))//確定是否是class method
$this->{$this->_action}();//用大括弧刮起來
else
echo "not member function:".$this->_action;
}
function sayHello(){
echo "Hello";
}
function sayHi(){
echo "Hi";
}
}
$act=new Action();
$act->setAction("sayHello");
$act->run();
$act->setAction("sayHi");
$act->run();
$act->setAction("say");
$act->run();
//output
Hello
Hi
not member function:say
2009年8月21日 星期五
Javascript的日曆套件
看到別人掛著好看的,想想自己也來掛一個
於是找到了一套JS Calendar
http://www.dynarch.com/projects/calendar/
目前在左邊小工具已經掛上去了
這邊順便放一個展示
功能很多,不過這裡我純粹當擺飾用
於是找到了一套JS Calendar
http://www.dynarch.com/projects/calendar/
目前在左邊小工具已經掛上去了
這邊順便放一個展示
功能很多,不過這裡我純粹當擺飾用
作品:jQuery實作slidingWindow
今天心血來潮,想要寫一個網頁版的slidingWindow效果
也就是一次只能顯示特定單位的Block
設計方法是使用遮罩(Mask)的方式,主要顯示區塊的部分是黑色的Mask,然後有一條輸送帶(Slider),載者輸送單位(Item Block)
如圖
基本架構大概是長成下面這樣
有這架構之後,之後的動作跟設定就是jQuery的工作了
下面是成果,共有三個Block,可以向左向右移動
也就是一次只能顯示特定單位的Block
設計方法是使用遮罩(Mask)的方式,主要顯示區塊的部分是黑色的Mask,然後有一條輸送帶(Slider),載者輸送單位(Item Block)
如圖
基本架構大概是長成下面這樣
<div class=”Mask”>
<div class=”silder”>
<div class=”itemblock”></div>
<div class=”itemblock”></div>
<div class=”itemblock”></div>
</div>
</div>
有這架構之後,之後的動作跟設定就是jQuery的工作了
下面是成果,共有三個Block,可以向左向右移動
IE下隱藏iframe的border
今天在測網頁的時候,想不到在Blogger無法正確顯示
我又懶得再去改他css,此時就想到使用iframe的方式去避開Blogger的CSS
原本我用設css的border為none的方式,想隱藏iframe,讓我的子網頁顯示看起來正常一點
但是想不到這方法只能在非IE下有用,這可真傷腦筋
後來找了網路上的資料,找到了設置frameborder、border、cellspacing三個屬姓讓IE的iframe border可以消失
我又懶得再去改他css,此時就想到使用iframe的方式去避開Blogger的CSS
原本我用設css的border為none的方式,想隱藏iframe,讓我的子網頁顯示看起來正常一點
<iframe src="xxx" style=" border:none" width="500" height="400"></iframe>
但是想不到這方法只能在非IE下有用,這可真傷腦筋
後來找了網路上的資料,找到了設置frameborder、border、cellspacing三個屬姓讓IE的iframe border可以消失
<iframe frameborder="0" border="0" cellspacing="0" src="xxx" style=" border:none" width="500" height="400"></iframe>
2009年8月20日 星期四
Smarty隨手筆記
這兩天閒來無事稍微研究了一下Smarty
Smarty是PHP用的一套樣版引擎
這東西就像是.NET的MasterPage,可以把頁面Template(樣版化)動態輸出
這樣一來就可以標準化網頁,不過個人不喜歡MasterPage的作法就是了
之前旗標也有出Smarty的書籍,不過網路上已經也有很多相關教學了
Smarty並不是很龐大,說明手冊花個兩三個小時大概就能讀完了
加上有前人很熱情的放出中文化中說明手冊,要自學也不用花什麼工夫
附上幾個我參考到的網站
當初覺得Smarty應該要花不少時間去學,真的開始看說明手冊以後其實不然
不考慮研究核心code的話,其實很快就能把整個功能面跟觀念說完了
上面幾篇文章都說的非常清楚了,下面只是我一些研究過程的隨筆
Extended Setup這篇有附上一段程式碼,這段code很重要
他建議我們擴充Smarty類別,把一些設定都先設定好
一開始要指定幾個資料夾,template_dir、compile_dir、config_dir、cache_dir
這四個最常用的,其他還有一些延伸資料夾可以指定,但是在此先不探討
而我照自己的需求去擴展一個Smarty,並創造一個smartyDir資料夾,下面放Smarty須要用到的資料夾
我把類別庫放在Smarty/libs下面,只要include其中的Smarty.class.php就可以了
我先在templates資料夾裡面建一個樣版檔案mytemp.tp
mytemp.tp內容
其中{$page}是Smarty可用的變數,將來可以用來替換自己想要的內容
變數的使用方法可以參考Variables這篇說明文件
簡介幾種常用的方式
之後php程式碼的部分就可以用assign指派我們想要的內容
執行結果
題外話,一開始我一直以為display() 函式是去程式同一個資料夾找樣版
所以一開始我沒把樣版放在templates資料夾裡面
所以一直會出現錯誤訊息
那剛剛秀出網頁做了些什麼呢?
首先我display()去顯示templates資料夾下的mytemp.tp
之後會在我指定的編譯資料夾templates_c下產生一個編譯過的檔案%%9B^9B3^9B3C2773%%mytemp.tp.php,此時他還是一個php的動態檔
來看一下他編譯了什麼東西出來
原來的樣版檔案,變成一個我們都很熟悉的PHP檔,Smarty變數的部分被PHP碼所取代
但是這樣很慢,要把樣版(Template)解譯成PHP檔,又要把PHP檔編譯成網頁
所以Smarty提供了cache的機制
當我設定cache的時候,,他會在我指定的cache資料夾產生一個已經編譯好的靜態網頁
這樣下次要access的時候直接用這個就可以了,不用重新編譯
來看看cache的內容
除了原本編譯好的網頁之外,還有一串header包括了timestamp
cache並不會永遠存在,過了一段時間後就會被刪除,預設是一個小時
可以透過cache_lifetime修改生存時間
不過如果同個樣版有多種內容的話(ex:資料庫的資料),就必須設定cache_id作辨別
一般會用user下的query作hash來產生cache_id
另外我在寫程式的時候,發現他會跟css碼或者javascript相衝,因為他的阻斷符號是{跟}
正好跟css設定方法有衝突,可以透過left_delimiter跟right_delimiter重新設定阻斷符號
像我是設定成,這樣就不會跟css碼相衝了
之後我在標記Smarty變數就會從
變成用下面這種方式
因為是用HTML註解的方式去從新包裝,這樣一來也比較不會有問題
其他更多的內容,包括註冊自己的函式跟區塊、if else 、loop迴圈等等,就請去翻說明手冊啦
手冊有更多詳盡的內容
Smarty是PHP用的一套樣版引擎
這東西就像是.NET的MasterPage,可以把頁面Template(樣版化)動態輸出
這樣一來就可以標準化網頁,不過個人不喜歡MasterPage的作法就是了
之前旗標也有出Smarty的書籍,不過網路上已經也有很多相關教學了
Smarty並不是很龐大,說明手冊花個兩三個小時大概就能讀完了
加上有前人很熱情的放出中文化中說明手冊,要自學也不用花什麼工夫
附上幾個我參考到的網站
- Smarty 官網:這是一定會參考到的 最新的文件還有下載
- Smarty入門:整理非常好的部落格,對於基礎功能跟觀念看這篇就對了
- Smarty中文說明手冊:英文不好,還有這個可以看,台灣PHP聯盟上的資源
當初覺得Smarty應該要花不少時間去學,真的開始看說明手冊以後其實不然
不考慮研究核心code的話,其實很快就能把整個功能面跟觀念說完了
上面幾篇文章都說的非常清楚了,下面只是我一些研究過程的隨筆
Extended Setup這篇有附上一段程式碼,這段code很重要
class Smarty_GuestBook extends Smarty {
function Smarty_GuestBook()
{
$this->Smarty();
$this->template_dir = '/web/www.example.com/guestbook/templates/';
$this->compile_dir = '/web/www.example.com/guestbook/templates_c/';
$this->config_dir = '/web/www.example.com/guestbook/configs/';
$this->cache_dir = '/web/www.example.com/guestbook/cache/';
$this->caching = true;
$this->assign('app_name', 'Guest Book');
}
}
他建議我們擴充Smarty類別,把一些設定都先設定好
一開始要指定幾個資料夾,template_dir、compile_dir、config_dir、cache_dir
這四個最常用的,其他還有一些延伸資料夾可以指定,但是在此先不探討
- template_dir:樣版網頁放置地方,使用display() 函式的時候會去template_dir指定的地方尋找樣版
預設是./templates - compile_dir:Smarty會把樣版網頁先編譯成對應格式,這是編譯結果放的網頁,預設是./templates_c
- config_dir:Smarty允許事先弄一些設定檔出來,預設是放./configs
使用config_load() 載入config的時候他會去config_dir指定的資料夾找檔案
他官網提供的config編寫範例
# global variables
pageTitle = "Main Menu"
bodyBgColor = #000000
tableBgColor = #000000
rowBgColor = #00ff00
[Customer]
pageTitle = "Customer Info"
[Login]
pageTitle = "Login"
focus = "username"
Intro = """This is a value that spans more
than one line. you must enclose
it in triple quotes."""
# hidden section
[.Database]
host=my.example.com
db=ADDRESSBOOK
user=php-user
pass=foobar - cache_dir:如果有設定快取(caching是true),他會產生一份compile_dir裡面編譯檔的最後輸出
預設資料夾是 ./cache
而我照自己的需求去擴展一個Smarty,並創造一個smartyDir資料夾,下面放Smarty須要用到的資料夾
我把類別庫放在Smarty/libs下面,只要include其中的Smarty.class.php就可以了
include_once ('Smarty/libs/Smarty.class.php');
define("APPDIR","smartyDir/");
class MySmarty extends Smarty{
function MySmarty(){
$this->template_dir=APPDIR."templates";
$this->compile_dir=APPDIR."templates_c";
$this->config_dir=APPDIR."config_dir";
$this->cache_dir=APPDIR."cache";
}
/*更改阻斷符號 預設是{跟}*/
function setDelimiter($Lcode,$Rcode)
{
$this->left_delimiter=$Lcode;
$this->right_delimiter="$Rcode";
}
}
?>
我先在templates資料夾裡面建一個樣版檔案mytemp.tp
mytemp.tp內容
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
{$page}
</body>
</html>
其中{$page}是Smarty可用的變數,將來可以用來替換自己想要的內容
變數的使用方法可以參考Variables這篇說明文件
簡介幾種常用的方式
- {$foo} <-- displaying a simple variable (non array/object)
指派一般變數,使用assign指派內容
$tp1=new MySmarty();
$tp1->assign("foo","Hello"); - {$foo[4]} <-- display the 5th element of a zero-indexed array
指派一個陣列
$arr=array(1,2,3,4,5);
$tp1->assign("foo",$arr); - {$foo.bar} <-- display the "bar" key value of an array, similar to PHP $foo['bar']
指派關聯陣列
$arr=array('bar'=>'I am God');
$tp1->assign("foo",$arr); - {$foo->bar} <-- display the object property "bar"
- {$foo->barf()} <-- display the return value of object method "bar"
指派一個物件
class Foo{
var $bar;
function barf(){......}
}
$obj=new Foo();
$tp1->assign("foo",$obj); {#foo#} <-- display the config file variable "foo"
使用config_load() 載入的設定內容
ex:有個conf.txt內容是foo=MyGod
之後php程式碼的部分就可以用assign指派我們想要的內容
$tp2=new MySmarty();
$tp2->assign("page","Hello Smarty");/*指派Smarty變數內容*/
$tp2->caching=true;/*開啟快取*/
$tp2->display("mytemp.tp");/*顯示網頁*/
執行結果
題外話,一開始我一直以為display() 函式是去程式同一個資料夾找樣版
所以一開始我沒把樣版放在templates資料夾裡面
所以一直會出現錯誤訊息
Smarty error: unable to read resource........
那剛剛秀出網頁做了些什麼呢?
首先我display()去顯示templates資料夾下的mytemp.tp
之後會在我指定的編譯資料夾templates_c下產生一個編譯過的檔案%%9B^9B3^9B3C2773%%mytemp.tp.php,此時他還是一個php的動態檔
來看一下他編譯了什麼東西出來
<?php /* Smarty version 2.6.26, created on 2009-08-21 02:07:52
compiled from mytemp.tp */ ?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<?php echo $this->_tpl_vars['page']; ?>
</body>
</html>
原來的樣版檔案,變成一個我們都很熟悉的PHP檔,Smarty變數的部分被PHP碼所取代
但是這樣很慢,要把樣版(Template)解譯成PHP檔,又要把PHP檔編譯成網頁
所以Smarty提供了cache的機制
當我設定cache的時候,,他會在我指定的cache資料夾產生一個已經編譯好的靜態網頁
這樣下次要access的時候直接用這個就可以了,不用重新編譯
來看看cache的內容
130
a:4:{s:8:"template";a:1:{s:9:"mytemp.tp";b:1;}s:9:"timestamp";i:1250821113;s:7:"expires";i:1250824713;s:13:"cache_serials";a:0:{}}<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
Hello Smarty
</body>
</html>
除了原本編譯好的網頁之外,還有一串header包括了timestamp
cache並不會永遠存在,過了一段時間後就會被刪除,預設是一個小時
可以透過cache_lifetime修改生存時間
不過如果同個樣版有多種內容的話(ex:資料庫的資料),就必須設定cache_id作辨別
一般會用user下的query作hash來產生cache_id
另外我在寫程式的時候,發現他會跟css碼或者javascript相衝,因為他的阻斷符號是{跟}
正好跟css設定方法有衝突,可以透過left_delimiter跟right_delimiter重新設定阻斷符號
像我是設定成,這樣就不會跟css碼相衝了
$tp1->setDelimiter("<!--{","}--<");/*這是我自定的函式,請參考上方的MySmarty*/
之後我在標記Smarty變數就會從
......
{$page}
......
變成用下面這種方式
<!--{$page}-->
因為是用HTML註解的方式去從新包裝,這樣一來也比較不會有問題
其他更多的內容,包括註冊自己的函式跟區塊、if else 、loop迴圈等等,就請去翻說明手冊啦
手冊有更多詳盡的內容
都可以找到相對應的翻譯
備註:上面的連結Smarty中文說明手冊
2009年8月13日 星期四
CSS設計必備-好用的IETester
昨天請朋友幫我看Blog,沒想到他跟我說他用IE8看我Blog版面亂掉
由於手上只有firefox跟opera、IE6三種瀏覽器,原以為這三種固好
應該都沒問題了,沒想到IE7後還是出現了問題
這真是CSS設計一大難點
後來找了一套IETester,目前的版本可以測試IE5.5~IE8這些版本
真替我解決了不少困擾,下面是網址
http://www.my-debugbar.com/wiki/IETester/HomePage
之後就可以很容易進行一些CSS hack的技術了
舉個例子,想要設置屬性的時候
或者想要設置元素
其它還有很多CSS hack方法
這裡連結兩個我覺得整理還蠻詳細的部落格
http://flash-silverlight.blogspot.com/2009/03/css-hackie6ie7ie8firefoxopera.html
http://ezcshi.pixnet.net/blog/post/13325989
由於手上只有firefox跟opera、IE6三種瀏覽器,原以為這三種固好
應該都沒問題了,沒想到IE7後還是出現了問題
這真是CSS設計一大難點
後來找了一套IETester,目前的版本可以測試IE5.5~IE8這些版本
真替我解決了不少困擾,下面是網址
http://www.my-debugbar.com/wiki/IETester/HomePage
之後就可以很容易進行一些CSS hack的技術了
舉個例子,想要設置屬性的時候
margin:0px;/*原始CSS屬姓設置,firefox跟IE等都適用,我通常用來處理firefox跟opera*/
*margin-top:-2px; /* IE系列適用,我通常用來處理IE7跟IE8*/
_margin-top:-2px; /* IE 6 only,我通常用來處理IE6*/
或者想要設置元素
#my { /*通用設置*/}
html>body #my{ /*針對firefox 去寫*/}
*+html>body #my{ /*針對IE7去寫*/}
其它還有很多CSS hack方法
這裡連結兩個我覺得整理還蠻詳細的部落格
http://flash-silverlight.blogspot.com/2009/03/css-hackie6ie7ie8firefoxopera.html
http://ezcshi.pixnet.net/blog/post/13325989
2009年8月12日 星期三
IE6 position:absolute 時使用Bottom的bug
這兩天在研究裝飾Blogger
在弄旁邊的綠色圓角區塊的時候,遇到了一點問題
我用的佈局
像這樣,用相對去包絕對
Header跟Floor用絕對配置去定位在最高跟最低位
因為當初作素材的時候沒注意到
導致Header的圖片過長
所以我才採取絕對定位(absolute )的方式去做
但是這樣缺出現了floor使用bottom去固定在底部的時候,floor整個走位的問題
floor跑去Container下面非常多的地方
後來發現這是IE6的一個Bug,必須在Container設置height:1%
像這樣
這樣才能避免用Bottom走位的問題
題外話
我當初在作素材的時候沒設計好,Header弄太長,導致會蓋住中間Content的底圖
但是用z-index卻又會造成漸層色沒辦法搭配好還有色差出現
這是當出架構沒有設計好出現的錯誤
照我一開始的設計,content跟content background是綁在一起的,
導致不是Header檔住content,或是反過來content backgroung檔住header
後來靈機一動,我是否能把content跟content backgeound分開?
就像下圖這樣
可以做到這樣的話,我就可以用Header照住Content Background 而不會遮住Content了
因此我只要多一層Div取代Content Background就可以了,如下
不過我後來floor就沒有用absolute 去定位了,只讓他直接掛在Content之下
因為發現如果Container的size有伸縮的話,IE6底下floor用絕對定位不會跟著改變position
導致整個版面變亂,雖然Firefox是會跟著調整position,但是還是力求統一
最後做個筆記,在弄z-index的時候要把position設定成absolute或relative,不然他不會起作用
在弄旁邊的綠色圓角區塊的時候,遇到了一點問題
我用的佈局
像這樣,用相對去包絕對
Header跟Floor用絕對配置去定位在最高跟最低位
因為當初作素材的時候沒注意到
導致Header的圖片過長
所以我才採取絕對定位(absolute )的方式去做
但是這樣缺出現了floor使用bottom去固定在底部的時候,floor整個走位的問題
floor跑去Container下面非常多的地方
後來發現這是IE6的一個Bug,必須在Container設置height:1%
像這樣
.container{
position:relative;
height:1%;
}
這樣才能避免用Bottom走位的問題
題外話
我當初在作素材的時候沒設計好,Header弄太長,導致會蓋住中間Content的底圖
但是用z-index卻又會造成漸層色沒辦法搭配好還有色差出現
這是當出架構沒有設計好出現的錯誤
照我一開始的設計,content跟content background是綁在一起的,
導致不是Header檔住content,或是反過來content backgroung檔住header
後來靈機一動,我是否能把content跟content backgeound分開?
就像下圖這樣
可以做到這樣的話,我就可以用Header照住Content Background 而不會遮住Content了
因此我只要多一層Div取代Content Background就可以了,如下
不過我後來floor就沒有用absolute 去定位了,只讓他直接掛在Content之下
因為發現如果Container的size有伸縮的話,IE6底下floor用絕對定位不會跟著改變position
導致整個版面變亂,雖然Firefox是會跟著調整position,但是還是力求統一
最後做個筆記,在弄z-index的時候要把position設定成absolute或relative,不然他不會起作用
2009年8月10日 星期一
javascript的URL編碼
之前我再用javascript作encoding的時候都是用escape
但是今天再弄Blogger效果的時候發現他對特定字元沒辦法作encode像是空白、+等等
像我想解析我分類裡的[Linux c/c++]就會解析錯誤
後來找到一篇不錯的文章
http://blog.miniasp.com/?tag=/urlencode
裡面對URL編碼有提供蠻不錯的解說
簡單來說主要就是分三類
測了結果只有第三類能幫我解析[Linux c/c++]給Blogger的feed供應
這之間的差異還真維妙
順帶一提!旁邊[學習手札]的分類滑動式列表差不多完成了,有機會把相關code放出來跟大家分享一下
但是今天再弄Blogger效果的時候發現他對特定字元沒辦法作encode像是空白、+等等
像我想解析我分類裡的[Linux c/c++]就會解析錯誤
後來找到一篇不錯的文章
http://blog.miniasp.com/?tag=/urlencode
裡面對URL編碼有提供蠻不錯的解說
簡單來說主要就是分三類
測了結果只有第三類能幫我解析[Linux c/c++]給Blogger的feed供應
這之間的差異還真維妙
順帶一提!旁邊[學習手札]的分類滑動式列表差不多完成了,有機會把相關code放出來跟大家分享一下
超連結執行javascript而不位移
今天寫AJAX的時候遇到的一個問題
我使用以下方式模擬按鈕
這應該算超連結執行javascript的標準寫法
但是卻發生了我點了之後會回到頂端的一個情況(我頁面很長 scroll有出現)
這樣一來我一些效果就會被抹煞,官感也很不好
不過部落格旁邊的網頁存檔給了我解決方法
改成如下
就不會有點下去後回到頁首的情況發生了
我使用以下方式模擬按鈕
<a href="#" onclick="javascript:put();">Push</a>
這應該算超連結執行javascript的標準寫法
但是卻發生了我點了之後會回到頂端的一個情況(我頁面很長 scroll有出現)
這樣一來我一些效果就會被抹煞,官感也很不好
不過部落格旁邊的網頁存檔給了我解決方法
改成如下
<a href="javascript:void(0)" onclick="javascript:put();">Push</a>
就不會有點下去後回到頁首的情況發生了
2009年8月8日 星期六
使用relative排版時空出來的區塊
當使用relative作位移的時候,原來的所佔的區塊並不會消失
因此會造成很大一塊空位在那邊
簡單舉個例子
此時沒有任何位移,因此看起來很平常
但是加了位移以後呢?
在此我把下方的區塊移到右方並排
如上所示,雖然下方區塊移到左邊了
但是,原來位置那一塊並沒有因此往上縮,造成下方平白無故多了500px的空白區域
有個解決的方法對付這種情況
就是在用一個div去包住他,並且鎖定位移後的長寬並設定overflow為hidden
如此一來,就可以解決多出來的區塊問題
結果如下,下方多出的500px已經消失了
因此會造成很大一塊空位在那邊
簡單舉個例子
css
div{ height:500px;width:400px; position:relative}
#one{ background-color:#9FF}
#two{ background-color:#F66}
html
<div id="one"></div>
<div id="two"></div>
此時沒有任何位移,因此看起來很平常
但是加了位移以後呢?
在此我把下方的區塊移到右方並排
css
div{ height:500px;width:400px; position:relative}
#one{ background-color:#9FF}
#two{ background-color:#F66;top:-500px; left:400px}
html
<div id="one"></div>
<div id="two"></div>
如上所示,雖然下方區塊移到左邊了
但是,原來位置那一塊並沒有因此往上縮,造成下方平白無故多了500px的空白區域
有個解決的方法對付這種情況
就是在用一個div去包住他,並且鎖定位移後的長寬並設定overflow為hidden
css
div{ height:500px;width:400px; position:relative}
#one{ background-color:#9FF}
#two{ background-color:#F66; top:-500px; left:400px}
#displayBlock{ height:500px; width:800px; overflow:hidden}
html
<div id="displayBlock">
<div id="one"></div>
<div id="two"></div>
</div>
如此一來,就可以解決多出來的區塊問題
結果如下,下方多出的500px已經消失了
案例研究:符水印的TextBox(使用jQuery)
在web 2.0常用的模組之一就是帶有浮水印效果的textbox
這個在實做上並不困難,現有的套件也非常多,不過今天是想探討jQuery的擴充函式實作方式
浮水印textbox,在失去焦點的狀態會有提示文字
在得到焦點會後,提示文字會消失,讓使用者可以正常輸入
今天來探討如何用jQuery去實現他
首先請準備兩個示範用的textbox
之後直接進入jQuery的部分
jQuery擴充常用的部分分下列三種
上面是擴充global member的部分,那如果想要擴充jQuery物件member呢?
可以使用jQuery.fn,他有兩種方式可以擴充函式
擴充一個jQuery物件function有什麼好處?
好處是我們可以用$(this)的方式去抓到觸發此函式的物件
也就是我們實作的方法
我們可以用這種方法來做一個屬於我們的plug-in
直接看程式碼
我們用jQuery.fn去擴充一個jquery物件函式watermark,他會接受兩個參數
一個是浮水印的顯示格式,一個是浮水印的顯示文字
一開始我們可以用val()這個函式去設定textbox的value
form相關物件的值都必須仰賴這個function去替我們抓
用$().text()可是什麼都抓不到
之後要設定失去焦點跟獲得焦點要做的事,在此我們用了toggleClass來替我們簡化作業
他會自動判斷物件是否有此class,有的話就移除他,沒有的話就增加他
這樣我們就不用自己去判斷了
設計理念很簡單
當失去焦點的時候,如果沒有輸入任何文字(str.length<=0)就回復浮水印狀態
當獲得焦點的時候,如果當前文字跟浮水印文字一樣,就清空浮水印訊息
最後就是享受成果的時候啦
這是初始化的部分,$(function(){})其效果就相當於$(document).ready(function(){});
也就是當DOM生成結束後要做的動作
此時我們只要一行程式碼,就可以替所有的textbox加上浮水印
$("input[type='text']")是抓取所有input底下所有type是text的物件
也就是我前面的textbox,然後執行我擴充的watermark函式
在這邊input是我設定的class name,在此只須要把文字顏色弄成灰色
如何!上面的程式碼是不是很像jQuery UI的使用方法阿
只要有這些知識,我們也能設計屬於我們的jQuery UI plug-in了
這個在實做上並不困難,現有的套件也非常多,不過今天是想探討jQuery的擴充函式實作方式
浮水印textbox,在失去焦點的狀態會有提示文字
在得到焦點會後,提示文字會消失,讓使用者可以正常輸入
今天來探討如何用jQuery去實現他
首先請準備兩個示範用的textbox
<input type="text" name="txt1" />
<input type="text" name="txt2" />
<input type="submit" />
之後直接進入jQuery的部分
jQuery擴充常用的部分分下列三種
jQuery.foo=function(){....}
這是最直接也最簡單的方式,這樣之後就可以用$.foo()的方式呼叫jQuery.extend({
foo:function(){}
});
第二種使用他提供的extend並使用物件形式擴充,一般來講比較建議這種方式
因為可讀性比較高jQuery.myplugin={
foo:function(){.......}
};
第三種如上,像這種中間在安插一個名稱,這樣一來可以防止名子跟別人的plug-in相衝
之後就可以使用$.myplugin.foo();的方式呼叫
而上面這作法也可以用jQuery.extend配合巢狀物件實現如下var myplugin={
myfunction:{
foo:function(){.......}
}
};
jQuery.extend(myplugin);
之後就可以使用$.myfunction.foo();的方式去呼叫了
上面是擴充global member的部分,那如果想要擴充jQuery物件member呢?
可以使用jQuery.fn,他有兩種方式可以擴充函式
jQuery.fn.test=function(){....}
第一個方法一樣最簡單,直接開一個新名稱去指向一個function
之後就可以使用$(obj).test();的方式去呼叫他jQuery.fn.extend({
bar:function(){.......}}
);
上面是第2個方法,使用他提供extend去做,這種作法可讀性比較高,之後可以用$(obj).bar()去呼叫他
擴充一個jQuery物件function有什麼好處?
好處是我們可以用$(this)的方式去抓到觸發此函式的物件
也就是我們實作的方法
我們可以用這種方法來做一個屬於我們的plug-in
直接看程式碼
jQuery.fn.watermark =function(className,message){
$(this).addClass(className);
$(this).val(message);
$(this).focus(function(){
var str=$(this).val();
if(str==message)
{
$(this).val("");
$(this).toggleClass(className);
}
});
$(this).blur(function(){
var str=$(this).val();
if(str.length<=0) {
$(this).toggleClass(className);
$(this).val(message);
}
});
}
我們用jQuery.fn去擴充一個jquery物件函式watermark,他會接受兩個參數
一個是浮水印的顯示格式,一個是浮水印的顯示文字
一開始我們可以用val()這個函式去設定textbox的value
form相關物件的值都必須仰賴這個function去替我們抓
用$().text()可是什麼都抓不到
之後要設定失去焦點跟獲得焦點要做的事,在此我們用了toggleClass來替我們簡化作業
他會自動判斷物件是否有此class,有的話就移除他,沒有的話就增加他
這樣我們就不用自己去判斷了
設計理念很簡單
當失去焦點的時候,如果沒有輸入任何文字(str.length<=0)就回復浮水印狀態
當獲得焦點的時候,如果當前文字跟浮水印文字一樣,就清空浮水印訊息
最後就是享受成果的時候啦
$(function(){
$("input[type='text']").watermark("input","請輸入字串");
}
這是初始化的部分,$(function(){})其效果就相當於$(document).ready(function(){});
也就是當DOM生成結束後要做的動作
此時我們只要一行程式碼,就可以替所有的textbox加上浮水印
$("input[type='text']")是抓取所有input底下所有type是text的物件
也就是我前面的textbox,然後執行我擴充的watermark函式
在這邊input是我設定的class name,在此只須要把文字顏色弄成灰色
,input{color:red}
如何!上面的程式碼是不是很像jQuery UI的使用方法阿
只要有這些知識,我們也能設計屬於我們的jQuery UI plug-in了
2009年8月7日 星期五
作品:Android遊戲設計-XGame
前幾個月花了點時間隨便弄出來的小遊戲
簡單來說,就是類似RPG遊戲製作大師那種東西
因為只是想研究android,就沒有特別去設計遊戲內容了
一開始是Menu的Activity,他可以選擇進入其他兩個Activity
總共三個選項,使用ListActivity配合相對排版實作出來
其中為了讓選單可以被選擇時出現圖片的特效
特別自訂了一個SelectAdapter,他去implement了BaseAdapter
因此我可以讓選單擁有提示圖片的效果,並且使用了全螢幕顯示特效。
Option的部分,他提供難易度選擇跟音量大小選擇的部分(音樂未實作),在這部份使用了TabActivity去做,並替每個Tab加上了各種圖示。
一開始我以為事件處裡的部分很簡單,想不到花了我不少工夫才搞好...
遊戲本體部分,他使用了SurfaceView去做Render的動作
因為他的Performace比較好,在繪圖上自由度也比較高。
其中使用了磁磚式遊戲的方式去實作
他是用Tiler(Block)去拼湊地圖的方式去實作,但是Android並沒有提供相關函式,所以我就自己模擬實做了類似相關類別。
而遊戲結束方法就是衝到終點的藍色區塊,以此就可以結束遊戲
圖中會有怪物發射飛彈來阻撓玩家前進,一擊斃命
中了藍色子彈是直接GG
恩.......不是什麼出色的作品,畢竟只是實驗性質下的產物
請客官不要太嚴厲
簡單來說,就是類似RPG遊戲製作大師那種東西
因為只是想研究android,就沒有特別去設計遊戲內容了
遊戲Menu
一開始是Menu的Activity,他可以選擇進入其他兩個Activity
總共三個選項,使用ListActivity配合相對排版實作出來
其中為了讓選單可以被選擇時出現圖片的特效
特別自訂了一個SelectAdapter,他去implement了BaseAdapter
因此我可以讓選單擁有提示圖片的效果,並且使用了全螢幕顯示特效。
Option
Option的部分,他提供難易度選擇跟音量大小選擇的部分(音樂未實作),在這部份使用了TabActivity去做,並替每個Tab加上了各種圖示。
一開始我以為事件處裡的部分很簡單,想不到花了我不少工夫才搞好...
Game
遊戲本體部分,他使用了SurfaceView去做Render的動作
因為他的Performace比較好,在繪圖上自由度也比較高。
其中使用了磁磚式遊戲的方式去實作
他是用Tiler(Block)去拼湊地圖的方式去實作,但是Android並沒有提供相關函式,所以我就自己模擬實做了類似相關類別。
而遊戲結束方法就是衝到終點的藍色區塊,以此就可以結束遊戲
圖中會有怪物發射飛彈來阻撓玩家前進,一擊斃命
中了藍色子彈是直接GG
恩.......不是什麼出色的作品,畢竟只是實驗性質下的產物
請客官不要太嚴厲
PHP 直接去call java類別
偶然之間看到了PHP呼叫使用java 類別的方法
就是用一套名為 PHP/Java Bridge的lib
就姑且研究了一下
原文章http://www.coolcode.cn/?action=show&id=166
呵呵!長長一串有夠複雜 舊版的安裝很花工夫
不過別擔心 新版的安裝方法已經減化很多了
在此只介紹新版的安裝法(舊版的大概也難找了)
首先請到官網下載php-java-bridge_5.4.4.2 這是目前的版本
不直接放載點,因為舊版的好像會被拿掉,請以官方為準
http://php-java-bridge.sourceforge.net/pjb/how_it_works.php
點download之後請點選php-java-bridge_5.4.4.2_documentation.zip下載
解壓之後,應該會看到一個JavaBridge.war
請在把他解壓縮,之後請放到localhost根目錄下
之後能就能(?)快樂的用PHP去call java的class了
用官網給的範例
看到沒有,簡單include就可以套用java類別了 哇哈哈
當然不會這麼簡單,執行後出現錯誤訊息
要include遠端檔案,必須開啟PHP權限,請修改php.ini的allow_url_fopen跟allow_url_include
如果找不到的話請自己補上,像我的php.ini就沒有allow_url_include選項
之後執行,又出現一個錯誤訊息
這是因為他新版會開一個proxy來代理java的動作,必須先執行他的JavaBridge.jar這隻程式
沒意外的話應該會放在JavaBridge\WEB-INF\lib下面
想想也是,他include一個遠程檔案,但是我並沒有那個server,所以他應該會在開一個proxy才對
程式執行畫面
範例是用8080port 就選8080port吧
因為我8080已經用過了 所以他會從8081開始
之後再執行就沒問題啦
就是用一套名為 PHP/Java Bridge的lib
就姑且研究了一下
原文章http://www.coolcode.cn/?action=show&id=166
呵呵!長長一串有夠複雜 舊版的安裝很花工夫
不過別擔心 新版的安裝方法已經減化很多了
在此只介紹新版的安裝法(舊版的大概也難找了)
首先請到官網下載php-java-bridge_5.4.4.2 這是目前的版本
不直接放載點,因為舊版的好像會被拿掉,請以官方為準
http://php-java-bridge.sourceforge.net/pjb/how_it_works.php
點download之後請點選php-java-bridge_5.4.4.2_documentation.zip下載
解壓之後,應該會看到一個JavaBridge.war
請在把他解壓縮,之後請放到localhost根目錄下
之後能就能(?)快樂的用PHP去call java的class了
用官網給的範例
<?php
require_once("http://localhost:8080/JavaBridge/java/Java.inc");
$System = java("java.lang.System");
echo $System->getProperties();
?>
看到沒有,簡單include就可以套用java類別了 哇哈哈
當然不會這麼簡單,執行後出現錯誤訊息
...URL file-access is disabled in the server configuration....
要include遠端檔案,必須開啟PHP權限,請修改php.ini的allow_url_fopen跟allow_url_include
allow_url_fopen = On
allow_url_include = On
如果找不到的話請自己補上,像我的php.ini就沒有allow_url_include選項
之後執行,又出現一個錯誤訊息
The requested method PUT is not allowed for the URL /JavaBridge/JavaBridge.phpjavabridge........
Check the back end log for OutOfMemoryErrors......
這是因為他新版會開一個proxy來代理java的動作,必須先執行他的JavaBridge.jar這隻程式
沒意外的話應該會放在JavaBridge\WEB-INF\lib下面
想想也是,他include一個遠程檔案,但是我並沒有那個server,所以他應該會在開一個proxy才對
程式執行畫面
範例是用8080port 就選8080port吧
因為我8080已經用過了 所以他會從8081開始
之後再執行就沒問題啦
2009年8月4日 星期二
Dreamweave的jQuery套件
今天偶然發現我在旁邊放的連結jQuery中文說明手冊
裡面有放Dreamweave的jQuery plug-in
點進去後右上方會jQuery 1.3 API 離線版下載
進去之後找自己Dw的版本 像我是CS4就選jQuery_api_for_dw4.rar
解壓之後執行裡面的
跳出安裝畫面後直接按接受就行了
之後就可以用Dw就可以跳出jQuery的提示程式碼啦
裡面有放Dreamweave的jQuery plug-in
點進去後右上方會jQuery 1.3 API 離線版下載
進去之後找自己Dw的版本 像我是CS4就選jQuery_api_for_dw4.rar
解壓之後執行裡面的
跳出安裝畫面後直接按接受就行了
之後就可以用Dw就可以跳出jQuery的提示程式碼啦
2009年8月3日 星期一
PHP:中文檔案上傳及上傳大小限制
今天在弄檔案上傳的程式
途中遇到了一些問題,第一個就是中文檔案無法上傳,另一個則是檔案太大無法上傳
首先看一下上傳檔案程式的原理
HTML部分
檔案上傳form的兩個重點,method要設成post,enctype要設成multipart/form-data
之後瀏覽檔案的input的name要設定,這樣才能被PHP所用,之後按下submit
檔案會被上傳到server的temp資料夾,等待我們處裡
PHP的部分
<input type="file" name="userfile" />
對照HTML的設定的name可以用$_FILE來獲得檔案資訊
這邊以name設成userfile為例
之後可以使用move_uploaded_file()把上傳的檔案從暫存資料夾移動到指定資料夾
不過在此之前記得先用is_uploaded_file()檢察是否是"上傳"的檔案
因為他有個漏洞,可能會被攻擊
這個漏洞的說明請參考這篇
http://seclists.org/bugtraq/2000/Sep/0237.html
再來就回到我們的問題
首先是中文檔案無法上傳,主要是PHP某些檔案控制的函式沒辦法控制utf-8的中文
所以必須改成big5的格式,如果目錄或檔案要包含中文的話
以我寫的程式為例
改成
透過iconv函式編碼後就可以解決了
至於檔案上傳限制問題,必須修改php.ini的兩個地方
要破除檔案大小限制 設定php.ini的 post_max_size 與 upload_max_filesize
這樣就可以上傳自己希望大小的檔案
途中遇到了一些問題,第一個就是中文檔案無法上傳,另一個則是檔案太大無法上傳
首先看一下上傳檔案程式的原理
HTML部分
<form action="conference_upload.php" method="post" enctype="multipart/form-data">
<div style="text-align:left"><span style="margin-left:12px">姓名:</span><span style="margin-left:28px">
<input type="text" name="username" /></span></div>
<span>上傳檔案:</span><span><input type="file" name="userfile" /></span>
<hr/>
<div style="text-align:right; margin-right:12px"><input type="submit" value="upload" /></div>
</form>
檔案上傳form的兩個重點,method要設成post,enctype要設成multipart/form-data
之後瀏覽檔案的input的name要設定,這樣才能被PHP所用,之後按下submit
檔案會被上傳到server的temp資料夾,等待我們處裡
PHP的部分
<input type="file" name="userfile" />
對照HTML的設定的name可以用$_FILE來獲得檔案資訊
這邊以name設成userfile為例
- $_FILES['userfile']['tmp_name'] :得到在temp資料夾的檔案,也就是在user上傳的檔案
- $_FILES['userfile']['name']:得到上傳的檔案名稱
- $_FILES['userfile']['size']:得到上傳的檔案大小
- $_FILES['userfile']['type']:得到上傳的檔案類型
- $_FILES['userfile']['error']:得到上傳錯誤時代碼
之後可以使用move_uploaded_file()把上傳的檔案從暫存資料夾移動到指定資料夾
不過在此之前記得先用is_uploaded_file()檢察是否是"上傳"的檔案
因為他有個漏洞,可能會被攻擊
這個漏洞的說明請參考這篇
http://seclists.org/bugtraq/2000/Sep/0237.html
再來就回到我們的問題
首先是中文檔案無法上傳,主要是PHP某些檔案控制的函式沒辦法控制utf-8的中文
所以必須改成big5的格式,如果目錄或檔案要包含中文的話
以我寫的程式為例
$user=$_POST['username'];
$userdir='conference\\'.$user.'_'.date("Y-m-d");
$path=$userdir.'\\'.$_FILES['userfile']['name'];
move_uploaded_file($_FILES['userfile']['tmp_name'],$path);
改成
$user=$_POST['username'];
$userdir=iconv('utf-8','big5','conference\\'.$user.'_'.date("Y-m-d"));
$path=$userdir.'\\'.iconv('utf-8','big5',$_FILES['userfile']['name']);
move_uploaded_file($_FILES['userfile']['tmp_name'],$path);
透過iconv函式編碼後就可以解決了
至於檔案上傳限制問題,必須修改php.ini的兩個地方
要破除檔案大小限制 設定php.ini的 post_max_size 與 upload_max_filesize
這樣就可以上傳自己希望大小的檔案
PHP:ini_set可更改項目
某些時候我們會用ini_set這個函式來動態更改php.ini的內容
但是並非每個項目都可更改
http://tw.php.net/manual/en/ini.php#ini.list
上面節錄一段文字
也就是說在清單上Changeable項目被標示為 PHP_INI_ALL或是 PHP_INI_USER的選項
才能被ini_set修改
php.ini清單請參照
http://tw.php.net/manual/en/ini.list.php
但是並非每個項目都可更改
http://tw.php.net/manual/en/ini.php#ini.list
上面節錄一段文字
You can use the ini_set() function to set a directive's
value in your scripts provided the "CHANGEABLE" attribute in the above chart is
PHP_INI_USER or PHP_INI_ALL.
也就是說在清單上Changeable項目被標示為 PHP_INI_ALL或是 PHP_INI_USER的選項
才能被ini_set修改
php.ini清單請參照
http://tw.php.net/manual/en/ini.list.php
2009年8月2日 星期日
PHP:URL利器-http_build_query及parse_url
偶然間看到的不錯用的兩個函式http_build_query及parse_url
他是PHP 5加入的函式,主要可以幫助我們置作GET跟POST要用的query
PHP手冊
http://tw.php.net/http_build_query
平常我們要下query的時候都會自己組合
如今PHP提供我們這個函式,就可以用可讀性比較高的方法來替我們做了
上面是一個比較簡單的例子,透過一個關聯式array來替我們製造http query
上面的array內容可以替換成我們須要的變數來優美的去置作query
這樣一來就能更有彈性的來撰寫我們的程式,而不用暴力的字串連結來下query
手冊裡面有更多進階的範例可以看
PHP手冊
http://tw.php.net/manual/en/function.parse-url.php
如同字面意思,可以幫我們解析一個URL,他會幫我們把URL拆解成幾個部份
直接拿手冊上的例子來看
他的output
這個函式會回傳一個關連式陣列,如此一來可以替我們的程式增加可讀性
http_build_query()
他是PHP 5加入的函式,主要可以幫助我們置作GET跟POST要用的query
PHP手冊
http://tw.php.net/http_build_query
平常我們要下query的時候都會自己組合
http://xxx.xxx/xxx?id=1&title=2
如今PHP提供我們這個函式,就可以用可讀性比較高的方法來替我們做了
$query=array(
'id'=>1,
'title'=>2
);
echo http_build_query($query);
output:id=1&title=2
上面是一個比較簡單的例子,透過一個關聯式array來替我們製造http query
上面的array內容可以替換成我們須要的變數來優美的去置作query
$id=1;
$title=2;
$query=array(
'id'=>$id,
'title'=>$title
);
echo http_build_query($query);
這樣一來就能更有彈性的來撰寫我們的程式,而不用暴力的字串連結來下query
手冊裡面有更多進階的範例可以看
parse_url
PHP手冊
http://tw.php.net/manual/en/function.parse-url.php
如同字面意思,可以幫我們解析一個URL,他會幫我們把URL拆解成幾個部份
- scheme - e.g. http
- host
- port
- user
- pass
- path
- query - after the question mark ?
- fragment - after the hashmark #
直接拿手冊上的例子來看
$url = 'http://username:password@hostname/path?arg=value#anchor';
print_r(parse_url($url));
他的output
Array
(
[scheme] => http
[host] => hostname
[user] => username
[pass] => password
[path] => /path
[query] => arg=value
[fragment] => anchor
)
這個函式會回傳一個關連式陣列,如此一來可以替我們的程式增加可讀性
PHP:flush跟ob_flush
今天看到一個範例 用了flush跟ob_flush 在想到底有什麼不同
後來查了PHP手冊
http://tw.php.net/manual/en/book.outcontrol.php
在順序上,必須先用ob_flush再用flush
ob_flush是把在PHP緩衝區(output_buffer)(假設有打開)的東西輸出,但並不是立刻輸出到螢幕上
flush則是把非PHP緩衝區,伺服器上準備輸出的資料輸出到瀏覽器上"顯示出來"
因此順序上必須先用ob_flush()把緩衝區上的資料輸出後,才能用flush()把從緩衝區輸出的資料給列印到螢幕上,不然光用ob_flush(),把緩衝區清空他並不會立刻把資料輸出到螢幕上
而只用flush(),資料全部在緩衝區他也沒東西可列印到螢幕上
網路上最常看到的例子
上面這隻程式會一秒輸出一個數字到螢幕上,可以試試把flush()或ob_flush()其中一個拿掉
就會變成十秒後全部輸出,而不是一次輸出一個字
上述狀況是在output_buffer打開的情況下,因為echo的東西會先把資料存到output_buffer
再從output_buffer頃印到螢幕上
上述程式碼結果其實等同於
在output_buffer關閉的情況下,輸出資料不會搬到緩衝區,可以直接用flush()把他頃印出來
至於output_buffer打開的方式有兩種
第一種是修改php.ini的output_buffer選項
改成
N是一個數字,文件上建議是改成4096
第二種方法則是用他提供的ob_start()函數
用法可以參照手冊,而要關閉output_buffer則是使用ob_end_clean 或ob_end_flush
所以前面提到的例子完整一點,不修改php.ini的話應該是要
那就有個疑問,為何這麼麻煩要把資料先搬到緩衝呢
有個說法是可以提高效率
而官方另一種有說服力的理由,配合header修改
http://tw.php.net/manual/en/outcontrol.examples.basic.php
上面這段程式,如果在output_buffer關閉的情況下使使用,會出現
這段錯誤訊息
為什麼呢?看一下setcookie的說明
上面的說明很清楚了,會動到header的部分,但是前幾篇文章有提到
header輸出之前不能有任何output到瀏覽器螢幕上,不然就會出現上面的error
http://hatsukiakio.blogspot.com/2009/07/cannot-send-session-cache-limiter.html
所以可以透過output_buffer先把輸出資料鎖在output_buffer裡面
這樣就可以執行header相關函數了
後來查了PHP手冊
http://tw.php.net/manual/en/book.outcontrol.php
在順序上,必須先用ob_flush再用flush
ob_flush();
flush();
ob_flush是把在PHP緩衝區(output_buffer)(假設有打開)的東西輸出,但並不是立刻輸出到螢幕上
flush則是把非PHP緩衝區,伺服器上準備輸出的資料輸出到瀏覽器上"顯示出來"
因此順序上必須先用ob_flush()把緩衝區上的資料輸出後,才能用flush()把從緩衝區輸出的資料給列印到螢幕上,不然光用ob_flush(),把緩衝區清空他並不會立刻把資料輸出到螢幕上
而只用flush(),資料全部在緩衝區他也沒東西可列印到螢幕上
網路上最常看到的例子
for($i=0;$i<10;$i++)
{
echo $i;
ob_flush();
flush();
sleep(1);
}
上面這隻程式會一秒輸出一個數字到螢幕上,可以試試把flush()或ob_flush()其中一個拿掉
就會變成十秒後全部輸出,而不是一次輸出一個字
上述狀況是在output_buffer打開的情況下,因為echo的東西會先把資料存到output_buffer
再從output_buffer頃印到螢幕上
上述程式碼結果其實等同於
ob_end_clean();//關閉output_buffer
for($i=0;$i<10;$i++)
{
echo $i;
flush();
sleep(1);
}
在output_buffer關閉的情況下,輸出資料不會搬到緩衝區,可以直接用flush()把他頃印出來
至於output_buffer打開的方式有兩種
第一種是修改php.ini的output_buffer選項
output_buffer = off
改成
output_buffer = N
N是一個數字,文件上建議是改成4096
第二種方法則是用他提供的ob_start()函數
- ob_start — Turn on output buffering
用法可以參照手冊,而要關閉output_buffer則是使用ob_end_clean 或ob_end_flush
- ob_end_clean — Clean (erase) the output buffer and turn off output buffering
- ob_end_flush — Flush (send) the output buffer and turn off output buffering
所以前面提到的例子完整一點,不修改php.ini的話應該是要
ob_start();//打開output_buffer
for($i=0;$i<10;$i++)
{
echo $i;
ob_flush();
flush();
sleep(1);
}
ob_end_clean();//關閉output_buffer
那就有個疑問,為何這麼麻煩要把資料先搬到緩衝呢
有個說法是可以提高效率
而官方另一種有說服力的理由,配合header修改
http://tw.php.net/manual/en/outcontrol.examples.basic.php
ob_start();
echo "Hello\n";
setcookie("cookiename", "cookiedata");
ob_end_flush();
上面這段程式,如果在output_buffer關閉的情況下使使用,會出現
Cannot modify header information - headers already sent
這段錯誤訊息
為什麼呢?看一下setcookie的說明
setcookie() defines a cookie to be sent along with the rest of the HTTP headers.
Like other headers,cookies must be sent before any output from your script (this is a protocol restriction).
This requires that you place calls to this function prior to any output,
including <html> and <head> tags as well as any whitespace.
上面的說明很清楚了,會動到header的部分,但是前幾篇文章有提到
header輸出之前不能有任何output到瀏覽器螢幕上,不然就會出現上面的error
http://hatsukiakio.blogspot.com/2009/07/cannot-send-session-cache-limiter.html
所以可以透過output_buffer先把輸出資料鎖在output_buffer裡面
這樣就可以執行header相關函數了
P.S output_buffer必須夠大,不然output_buffer滿了他一樣會輸出到螢幕上
這樣的話header函數依然會有危險
2009年8月1日 星期六
PHP 學習筆記 header:下載與轉址等等
開始摸PHP也有幾天了,把一些心得PO上來
之前碰到一個須求,我要用PHP控制seriver上的檔案讓人下載
以前我都是用javascript的location.href轉址轉過去那個file
如果是一般二進位檔或許會正常進行下載動作,但是一些文字檔還是圖片檔
像是.txt,.doc等等,會照瀏覽器預設行為動作
但是我希望他統一都是用下載的方式
後來發現可以更改HTTP Request來控制瀏覽器的行為
在此我須要PHP的header函數幫我做這件事
http://tw.php.net/manual/en/function.header.php
開頭就說了header函數的功用
透過header函數我們可以修改 HTTP Header
而要讓瀏覽器啟動下載必要的一行函數
只要有這行,就可以把瀏覽器上的output變成一個file下載
而我最常用的範例如下
透過readfile把檔案內容全部輸出到瀏覽器後,透過header的修正,就會變成下載檔案的行為
同時也可以用echo來輸出一般文字檔
舉個簡單的例子
上面例子會通知瀏覽器下載檔案,檔名為hello.txt
這是比較簡便的做法,完整一點的例子如下,可以控制傳輸方式,檔案size等資訊
又或者可以控制檔案讀取方式
上面這段程式碼
如果加了header('Content-Disposition: attachment; filename="downloaded.pdf"');
這行會變成通知瀏覽器下載此pdf
如果不加,則是告訴瀏覽器output是pdf檔,瀏覽器會使用他預設讀取pdf的程式如adobe reader來作存取,如下圖是不加的執行結果
header還有許多奇妙的功用
像是防止網頁過期資訊
可以加上下面這行址令解決
同時可以用他達到轉址的效果如下
不過要記得一件事,使用header轉址的時候記得要加上exit或flush
來防止無法控制的結果
考慮下面一段程式碼
他最後結果會到yahoo而非google,因為header下了以後不會馬上執行
結果又執行了一次header函數把原先的目標給蓋掉了
但是改成
或是
就可以了,不過比較建議用第二種
如果用flush要避免flush之後再去修改header,譬如說
執行上面的程式會出現以下訊息
之前碰到一個須求,我要用PHP控制seriver上的檔案讓人下載
以前我都是用javascript的location.href轉址轉過去那個file
如果是一般二進位檔或許會正常進行下載動作,但是一些文字檔還是圖片檔
像是.txt,.doc等等,會照瀏覽器預設行為動作
但是我希望他統一都是用下載的方式
後來發現可以更改HTTP Request來控制瀏覽器的行為
在此我須要PHP的header函數幫我做這件事
http://tw.php.net/manual/en/function.header.php
開頭就說了header函數的功用
header — Send a raw HTTP header
透過header函數我們可以修改 HTTP Header
而要讓瀏覽器啟動下載必要的一行函數
header('Content-type:application/force-download');
只要有這行,就可以把瀏覽器上的output變成一個file下載
而我最常用的範例如下
header('Content-type:application/force-download'); //告訴瀏覽器 為下載
header('Content-Transfer-Encoding: Binary'); //編碼方式
header('Content-Disposition:attachment;filename='.$filename); //檔名
@readfile($filename);
透過readfile把檔案內容全部輸出到瀏覽器後,透過header的修正,就會變成下載檔案的行為
同時也可以用echo來輸出一般文字檔
舉個簡單的例子
header('Content-type:application/force-download'); //告訴瀏覽器 為下載
header('Content-Transfer-Encoding: Binary'); //編碼方式
header('Content-Disposition:attachment;filename=hello.txt'); //檔名
echo 'Hello PHP';
上面例子會通知瀏覽器下載檔案,檔名為hello.txt
這是比較簡便的做法,完整一點的例子如下,可以控制傳輸方式,檔案size等資訊
<?php
$filename = "theDownloadedFileIsCalledThis.mp3";
$myFile = "/absolute/path/to/my/file.mp3";
$mm_type="application/octet-stream";
header("Cache-Control: public, must-revalidate");
header("Pragma: hack"); // WTF? oh well, it works...
header("Content-Type: " . $mm_type);
header("Content-Length: " .(string)(filesize($myFile)) );
header('Content-Disposition: attachment; filename="'.$filename.'"');
header("Content-Transfer-Encoding: binary\n");
readfile($myFile);
?>
又或者可以控制檔案讀取方式
// We'll be outputting a PDF
header('Content-type: application/pdf');
// It will be called downloaded.pdf
//header('Content-Disposition: attachment; filename="downloaded.pdf"');
// The PDF source is in original.pdf
readfile('2007.pdf');
上面這段程式碼
如果加了header('Content-Disposition: attachment; filename="downloaded.pdf"');
這行會變成通知瀏覽器下載此pdf
如果不加,則是告訴瀏覽器output是pdf檔,瀏覽器會使用他預設讀取pdf的程式如adobe reader來作存取,如下圖是不加的執行結果
header還有許多奇妙的功用
像是防止網頁過期資訊
警告: 網頁已經過期 已經使用您在表格傳送的資訊,來建立您要求的網頁。這個網頁已經無法再使用。基於安全性考量,Internet Explorer 不會自動為您重新傳送資訊。
可以加上下面這行址令解決
header ('Cache-Control: private, pre-check=0, post-check=0, max-age=0');
同時可以用他達到轉址的效果如下
header("Location: http://www.google.com.tw");
不過要記得一件事,使用header轉址的時候記得要加上exit或flush
來防止無法控制的結果
考慮下面一段程式碼
header("Location: http://www.google.com.tw");
sleep(1);
header("Location: http://www.yahoo.com.tw");
他最後結果會到yahoo而非google,因為header下了以後不會馬上執行
結果又執行了一次header函數把原先的目標給蓋掉了
但是改成
header("Location: http://www.google.com.tw");
flush();
sleep(1);
header("Location: http://www.yahoo.com.tw");
或是
header("Location: http://www.google.com.tw");
exit;
sleep(1);
header("Location: http://www.yahoo.com.tw");
就可以了,不過比較建議用第二種
如果用flush要避免flush之後再去修改header,譬如說
flush();
header("Location: http://www.yahoo.com.tw");
執行上面的程式會出現以下訊息
Cannot modify header information - headers already sent
攻略:nico影片下載教學
之前研究了youtube影片抓取方式後,就順便研究了一下niconico的檔案抓取方法
niconico是日本知名的影音分享平台,通常我們這種宅男都會很喜歡去逛
而他的影片要如何下載呢?
目前最常用的軟體就是 [BOON-SUTAZIO] 這套軟體,他是用IE的核心在跑
但是如果對用灌firefox的朋友來說,還要特定開一個瀏覽器實在麻煩
ptt的ybite大則有推廣一套名為 [Nicofox] 的plug-in
又或者firefox可以用HTTP 封包觀察plug-in 如 [FireBug] 或 [HttpFox]等來直接找出檔案位置
下面用FireBug舉個例如下
選擇[網路]這個tag,在選擇[all]
可以找到類似下面這種長像的網址
這就是實體檔案位置,可以放到flashget等續傳軟體下載
這邊low是指低畫質影片,正常畫質位置則不會有low這個字
那有沒有更直接的方法 連plug-in都不用裝呢
當然有,接下來介紹下面方法
首先呢 請先抓出nico影片的後置碼,譬如說
就是抓出sm5425174,然後用http://www.nicovideo.jp/api/getflv/代換如下
之後把組合後的新網址放到網址列按下enter進入後,會得到類似如下的一段code
但是這樣還沒結束,這段code是被encode過的,必須decode後才能用
decode可以用javascript的unescape函式
或者是提供decode功能的網頁,類似下面這個網頁
http://www.csie.ntu.edu.tw/~b94102/unescape.htm
不一定是要上面那個網頁,任何有提供URLDecode的網頁都可以
或者高興自己寫一個也行(反正也才一行程式碼)
又或是對URL encode的方式很熟,自行帶換也可以
英文字是不用改,只須對特殊符號作替換如下
上面換一換也能decode回來
解碼後的結果如下
看到沒有!紅色那段url=http://smile-clb52.nicovideo.jp/smile?v=5425174.41080low不就是我們要找的東西嗎?
如此一來就可以得到nico影片檔的實體檔案位置,輕鬆方便,連plug-in都不用裝
-----------------------------
題外話,後來寫了一個javascript抓取nico影片的程式,發現只能在IE上使用,查了一下原因
我是用AJAX去做的,但是Firefox會對cross-domain(跨網域)的XMLHttpRequest請求作出阻擋
所以必須使用類似PHP的script程式來當proxy
後來懶惰就沒有繼續寫了
niconico是日本知名的影音分享平台,通常我們這種宅男都會很喜歡去逛
而他的影片要如何下載呢?
方法一:使用軟體
目前最常用的軟體就是 [BOON-SUTAZIO] 這套軟體,他是用IE的核心在跑
但是如果對用灌firefox的朋友來說,還要特定開一個瀏覽器實在麻煩
ptt的ybite大則有推廣一套名為 [Nicofox] 的plug-in
又或者firefox可以用HTTP 封包觀察plug-in 如 [FireBug] 或 [HttpFox]等來直接找出檔案位置
下面用FireBug舉個例如下
選擇[網路]這個tag,在選擇[all]
可以找到類似下面這種長像的網址
http://smile-clb52.nicovideo.jp/smile?v=5425174.41080low
這就是實體檔案位置,可以放到flashget等續傳軟體下載
這邊low是指低畫質影片,正常畫質位置則不會有low這個字
那有沒有更直接的方法 連plug-in都不用裝呢
當然有,接下來介紹下面方法
方法二:抓出實體link編碼
首先呢 請先抓出nico影片的後置碼,譬如說
http://www.nicovideo.jp/watch/sm5425174
就是抓出sm5425174,然後用http://www.nicovideo.jp/api/getflv/代換如下
http://www.nicovideo.jp/api/getflv/sm5425174
之後把組合後的新網址放到網址列按下enter進入後,會得到類似如下的一段code
thread_id=1228159357&l=306&url=http%3A%2F%2Fsmile-clb52.nicovideo.jp%2Fsmile%3Fv%3D5425174.41080low&link=http%3A%2F%2Fwww.smilevideo.jp%2Fview%2F5425174%2F594488&ms=http%3A%2F%2Fmsg.nicovideo.jp%2F9%2Fapi%2F&user_id=594488&is_premium=0&nickname=Hatsuki&time=1249113823&done=true&ng_rv=1&hms=hiroba-test6.nicovideo.jp&hmsp=2532&hmst=1000000108&hmstk=1249113853.UtHSJn2X4wZFiWNekHQL-e-YtY4
但是這樣還沒結束,這段code是被encode過的,必須decode後才能用
decode可以用javascript的unescape函式
或者是提供decode功能的網頁,類似下面這個網頁
http://www.csie.ntu.edu.tw/~b94102/unescape.htm
不一定是要上面那個網頁,任何有提供URLDecode的網頁都可以
或者高興自己寫一個也行(反正也才一行程式碼)
又或是對URL encode的方式很熟,自行帶換也可以
英文字是不用改,只須對特殊符號作替換如下
- [%3A]:替換成[:]
- [%2F]:替換成[/]
- [%3F]:替換成[?]
- [%3D]:替換成[=]
上面換一換也能decode回來
解碼後的結果如下
thread_id=1228159357&l=306&url=http://smile-clb52.nicovideo.jp/smile?v=5425174.41080low&link=http://www.smilevideo.jp/view/5425174/594488&ms=http://msg.nicovideo.jp/9/api/&user_id=594488&is_premium=0&nickname=Hatsuki&time=1249113930&done=true&ng_rv=1&hms=hiroba-test7.nicovideo.jp&hmsp=2530&hmst=1000000126&hmstk=1249113960.RcySgXhjcWcgVTsbv2zEwT9_xI4
看到沒有!紅色那段url=http://smile-clb52.nicovideo.jp/smile?v=5425174.41080low不就是我們要找的東西嗎?
如此一來就可以得到nico影片檔的實體檔案位置,輕鬆方便,連plug-in都不用裝
-----------------------------
備註一下,上面提到的方法都要先登入nico後才有用,因為他會用session跟timestamp來驗證
題外話,後來寫了一個javascript抓取nico影片的程式,發現只能在IE上使用,查了一下原因
我是用AJAX去做的,但是Firefox會對cross-domain(跨網域)的XMLHttpRequest請求作出阻擋
所以必須使用類似PHP的script程式來當proxy
後來懶惰就沒有繼續寫了
2009年7月30日 星期四
攻略:javascript下載youtube影片(PHP+jQuery)
不知不覺blog文章來到第100篇
說來慚愧,雖然申請部落格是兩三年前的事情了
但是真的開始有用的習慣也是前幾個月才開始的
------------------------------------------------
今天因老師請託要下載youtube的影片
我就藉這個機會來研究他的原理
目前網路上的教學大概都是找出實體檔案的方式來下載youtube的檔案
常用程式碼如下
舉個例子
http://www.youtube.com/watch?v=hjTb2gR8rpE&feature=related
隨便開啟一個youtube影片,打開他的HTML原始碼觀看
之後找到flash影片參數的部分,也就是 swfArgs的部分
這部份知識請去摸一下flash就會知道了
他裡面帶很多參數,但是在此我們把問題簡化,只關心裡面的video_id跟t參數
之後我們只要把這兩個參數合併到youtube的網址就可以直接下載檔案如下
之後把他放到網址列按enter就可以下載影片了
那我們是否可以把這個工作自動化呢
當然可以,了解原理後,剩下的就只是字串處裡的問題而已
如何把兩個參數給抓出來
在此我們用jQuery+PHP實作一個簡單的範例
首先須要一個html檔當界面來接受我們網址的輸入
再簡單不過的一個範例,一個textbox跟一個button
用一個function,getFlv()來處理我們的需求
而jQuery的部分也很單純
首先使用$('#url')或得textbox,並用get函式把他從jQuery物件轉成DOM物件
這樣我們才能抓取他的value
之後用一個post的請求給我們處裡字串的程式 getYouyube.php(這邊我打錯字 但是我也不想改了)
送一個參數url,也就是我們輸入的youtube網址
之後用location.href轉址就可以自動下載了
至於PHP的部分,他只是一些字串處裡而已
首先用file_get_contents得到輸入網址的HTML原始碼
之後把它切割成一行一行的陣列 直到找到我們的目標swfArgs為止
之後我們用一個自定函式getArgs去抓出我們要的參數 video_id跟t
結果展示
功能非常陽春,而且是適用於目前的youtube
他以後若改版之類的就不保證啦
不過可以根據參數這部份來提供更多服務,譬如說畫質選擇、檔名等等
這部份就以後再說吧
說來慚愧,雖然申請部落格是兩三年前的事情了
但是真的開始有用的習慣也是前幾個月才開始的
------------------------------------------------
今天因老師請託要下載youtube的影片
我就藉這個機會來研究他的原理
目前網路上的教學大概都是找出實體檔案的方式來下載youtube的檔案
常用程式碼如下
JavaScript
一般FLV畫質 (貼上以下全段不要斷行就會出現下載)
javascript:window.location.href = 'http://youtube.com/get_video?video_id=' +
swfArgs['video_id'] + "&l=" + swfArgs['l'] + "&sk=" + swfArgs['sk'] + '&t=' +
swfArgs['t'];
HQ畫質 (貼上以下全段不要斷行就會出現下載)
javascript:window.location.href = 'http://youtube.com/get_video?video_id=' +
swfArgs['video_id'] + "&fmt=18" + "&l=" + swfArgs['l'] + "&sk=" +
swfArgs['sk'] + '&t=' + swfArgs['t'];
HD畫質 (貼上以下全段不要斷行就會出現下載)
javascript:window.location.href = 'http://youtube.com/get_video?video_id=' +
swfArgs['video_id'] + "&fmt=22" + "&l=" + swfArgs['l'] + "&sk=" +
原文網址
但是我覺得光這樣太無趣了點,於是在去研究了一下原理
開了Fiddler去看一下封包
youtube實體影片是像其底下的get_video這網頁要來的(其實看上面javascript碼就知道了)
他帶了許多參數,後來發現,如果不考慮畫面,直接下載純影像的話
其實必備只須要下面兩個參數就夠了
- video_id
- t
舉個例子
http://www.youtube.com/watch?v=hjTb2gR8rpE&feature=related
隨便開啟一個youtube影片,打開他的HTML原始碼觀看
之後找到flash影片參數的部分,也就是 swfArgs的部分
這部份知識請去摸一下flash就會知道了
var swfArgs = {"usef": 0, "fexp": "903900", "enablecsi": "1", "watermark": "http://s.ytimg.com/yt/swf/logo-vfl106645.swf,http://s.ytimg.com/yt/swf/hdlogo-vfl100714.swf", "sourceid": "yw", "video_id": "hjTb2gR8rpE", "l": 15, "fmt_map": "18/512000/9/0/115,34/0/9/0/115,5/0/7/0/0", "feature": "related", "sk": "nZDATrs2t38ie9xRcRK_a3mjI-RuKXhPC", "is_doubleclick_tracked": "1", "vq": null, "t": "vjVQa1PpcFPKYZQWD4_9jBe0ngheWegeZ2fbI7T0wM4=", "hl": "zh_TW", "plid": "AARv6bNtawhBJVmH", "keywords": "%E6%96%B0%E4%B8%96%E7%B4%80%E3%82%A8%E3%83%B4%E3%82%A1%E3%83%B3%E3%82%B2%E3%83%AA%E3%82%AA%E3%83%B3%2C%E7%B6%BE%E6%B3%A2%E8%82%B2%E6%88%90%E8%A8%88%E7%94%BB%2C%E3%82%A2%E3%82%B9%E3%82%AB%E8%A3%9C%E5%AE%8C%E8%A8%88%E7%94%BB%2CPS2", "cr": "TW", "fmt_url_map": "18%7Chttp%3A//v22.lscache7.c.youtube.com/videoplayback%3Fip%3D0.0.0.0%26sparams%3Did%252Cexpire%252Cip%252Cipbits%252Citag%252Cburst%252Cfactor%26itag%3D18%26ipbits%3D0%26signature%3D12986C2C910D07BD87B445AE1164DDDC8330C06A.4AC1217E49AC790C83083037590C528C82E6A187%26sver%3D3%26expire%3D1248973200%26key%3Dyt1%26factor%3D1.25%26burst%3D40%26id%3D8634dbda047cae91%2C34%7Chttp%3A//v3.lscache8.c.youtube.com/videoplayback%3Fip%3D0.0.0.0%26sparams%3Did%252Cexpire%252Cip%252Cipbits%252Citag%252Cburst%252Cfactor%26itag%3D34%26ipbits%3D0%26signature%3D1B606B2E46C0471A611386C163B6B18FB617D7AD.0CA6C95A06F6D8E55C99A4552B4066CB1CD541C6%26sver%3D3%26expire%3D1248973200%26key%3Dyt1%26factor%3D1.25%26burst%3D40%26id%3D8634dbda047cae91%2C5%7Chttp%3A//v6.lscache2.c.youtube.com/videoplayback%3Fip%3D0.0.0.0%26sparams%3Did%252Cexpire%252Cip%252Cipbits%252Citag%252Cburst%252Cfactor%26itag%3D5%26ipbits%3D0%26signature%3D14E5E77EB01FE7F0152AA1318492DFBDE6A42BA5.CA1E4504117C976ECC479DFF573BD96E3E9685D4%26sver%3D3%26expire%3D1248973200%26key%3Dyt1%26factor%3D1.25%26burst%3D40%26id%3D8634dbda047cae91", "sdetail": "f%3Arelated%2Crv%3A2yRxIwkBelc"};
他裡面帶很多參數,但是在此我們把問題簡化,只關心裡面的video_id跟t參數
.......
"video_id": "hjTb2gR8rpE"
"t": "vjVQa1PpcFPKYZQWD4_9jBe0ngheWegeZ2fbI7T0wM4="
......
之後我們只要把這兩個參數合併到youtube的網址就可以直接下載檔案如下
http://www.youtube.com/get_video?video_id=hjTb2gR8rpE&t=vjVQa1PpcFPKYZQWD4_9jBe0ngheWegeZ2fbI7T0wM4=
之後把他放到網址列按enter就可以下載影片了
那我們是否可以把這個工作自動化呢
當然可以,了解原理後,剩下的就只是字串處裡的問題而已
如何把兩個參數給抓出來
在此我們用jQuery+PHP實作一個簡單的範例
首先須要一個html檔當界面來接受我們網址的輸入
<body>
<input id="url" type="text" />
<input type="button" value="Get" onclick="getFlv();" />
</body>
再簡單不過的一個範例,一個textbox跟一個button
用一個function,getFlv()來處理我們的需求
而jQuery的部分也很單純
function getFlv(){
var url=$('#url').get(0).value;
$.post("getYouyube.php",{'url':url},function(data){
location.href='http://www.youtube.com/get_video?'+data
});
}
首先使用$('#url')或得textbox,並用get函式把他從jQuery物件轉成DOM物件
這樣我們才能抓取他的value
之後用一個post的請求給我們處裡字串的程式 getYouyube.php(這邊我打錯字 但是我也不想改了)
送一個參數url,也就是我們輸入的youtube網址
之後用location.href轉址就可以自動下載了
至於PHP的部分,他只是一些字串處裡而已
$html=file_get_contents($_POST['url']);
$arr=split("\n",$html);
$num=count($arr);
for($i=0;$i<$num;$i++)
{
if(ereg("swfArgs",$arr[$i]))
{
getArgs($arr[$i]);
}
}
首先用file_get_contents得到輸入網址的HTML原始碼
之後把它切割成一行一行的陣列 直到找到我們的目標swfArgs為止
之後我們用一個自定函式getArgs去抓出我們要的參數 video_id跟t
function getArgs($text)
{
$arr=split(",",$text);
$num=count($arr);
for($i=0;$i<$num;$i++)
{
$key=strtok($arr[$i],':');
$value=stripShell(strtok(':'));
if(strcmp(trim($key),"\"video_id\"")==0)
{
echo sprintf("%s=%s&",stripShell($key),$value);
}
else if(strcmp(trim($key),"\"t\"")==0)
{
echo sprintf("%s=%s&",stripShell($key),$value);
}
}
}
/*去頭尾字元*/
function stripShell($str)
{
return substr($str,2,-1);
}
結果展示
功能非常陽春,而且是適用於目前的youtube
他以後若改版之類的就不保證啦
不過可以根據參數這部份來提供更多服務,譬如說畫質選擇、檔名等等
這部份就以後再說吧
2009年7月28日 星期二
web學習-跳出式對話框 使用jQuery
雖然這對話框這東西已經有一大堆現成套件可以用了
但是基於求知的心態還是會想要知道他是怎麼弄的
下面一個自己寫的範例
很簡單的功能,就跳出一個訊息然後可以關掉
這個範例須要四個元素
-------
除了範例網頁之外,第三跟第四個元素,也就是Dialog對話框的Div可以隨便放
因為他們的位置是用絕對位置控制
先來觀察css設定的部分
這第一部分,為了跟舊firefox相容,所以必須連html tag也設定,而不能光設定body tag
在此把height設為100%,不然的話IE6的div元素沒有辦法延展至100%
並且margin設為0,避免延展後的div區塊跟瀏覽器有間隔(這邊也是IE的bug)
下面是不加margin: 0;的效果,明顯可以看出遮擋的div沒有完全填滿視窗
接著看其他css設定
在firefox就算height設成100%,但是會出現一個問題,他不像IE會自動填補scroll延展的部分,所以只要頁面有scroll並且往下拉就會破功
所以在此使用position:fixed來固定遮罩區塊,但是另一個問題出現了
就是IE不支持position:fixed這個屬性
所以我就利用了css hack的技巧,把IE挑出設定成position:absolute;
*html 是IE only的語法 可以拿來應付這種狀況
下圖是firefox使用position:absolute;來設定height:100%時的狀況
最後把z-index設置一下就ok了
之後就是jQuery的部分了,總共分成三大部分
第一部分,當DOM初始化之後,要先把對話框給隱藏起來
並且把遮罩div的透明度設成0.5
透明度設定請參照
http://hatsukiakio.blogspot.com/2009/07/jquerycss.html
第二部份是msg的div中,要關閉對話框的事件區動,說是關閉,也只是把dialog隱藏起來而已
第三部份,show出dialog,這部份比較雜一點
要show出對話框,只要把他的display屬性從none改成空值及可
之後可以用document.body的clientWidth跟clientHeight得到視窗的大小
再來有一點也是瀏覽器的問題,IE會把上面工具列的部分也算在視窗size裡
所以要用jQuery的$.browser.msie來判斷是不是IE來做修正
最後是得到scroll的位置,一開始我是用document.documentElement去取得
但是後來發現jQuery的+$(document).scrollTop()就能做到相同的事情了
但是基於求知的心態還是會想要知道他是怎麼弄的
下面一個自己寫的範例
很簡單的功能,就跳出一個訊息然後可以關掉
這個範例須要四個元素
- 一個看效果網頁,隨便弄一個就好了 這邊拿DW的範例當底(懶惰一下)
- 一個起動開啟Dialog事件的按鈕
<input type="button" value="叫出對話框" onclick="showDialog();" > - 一個遮住底頁的黑色不透明區塊
<div id="dialog"></div> - 真正要顯示訊息的區塊,他包含關閉Dialog事件的按鈕
<div id="msg">
<p>這是一個測試的對話框</p>
<input type="button" value="關閉" onclick="closeDialog();" />
</div>
-------
除了範例網頁之外,第三跟第四個元素,也就是Dialog對話框的Div可以隨便放
因為他們的位置是用絕對位置控制
先來觀察css設定的部分
html,body {
margin: 0;
padding: 0;
height:100%;
}
這第一部分,為了跟舊firefox相容,所以必須連html tag也設定,而不能光設定body tag
在此把height設為100%,不然的話IE6的div元素沒有辦法延展至100%
並且margin設為0,避免延展後的div區塊跟瀏覽器有間隔(這邊也是IE的bug)
下面是不加margin: 0;的效果,明顯可以看出遮擋的div沒有完全填滿視窗
接著看其他css設定
#dialog{
/* 非IE瀏覽用設定,使其長寬都延展至100% */
position:fixed;
top:0px;
left:0px;
width:100%;
height:100%;
margin:0px;
background-color:#000000;
z-index:1;
text-align:center;
}
*html #dialog{position:absolute;}/*IE舊瀏覽器用,設定絕對定位*/
#msg{ /*訊息區塊,背景設為白色,使用絕對定位*/
position:absolute;
top:0px;
left:0px;
background-color:#FFFFFF;
width:400px;
z-index:3;
}
在firefox就算height設成100%,但是會出現一個問題,他不像IE會自動填補scroll延展的部分,所以只要頁面有scroll並且往下拉就會破功
所以在此使用position:fixed來固定遮罩區塊,但是另一個問題出現了
就是IE不支持position:fixed這個屬性
所以我就利用了css hack的技巧,把IE挑出設定成position:absolute;
*html 是IE only的語法 可以拿來應付這種狀況
下圖是firefox使用position:absolute;來設定height:100%時的狀況
最後把z-index設置一下就ok了
之後就是jQuery的部分了,總共分成三大部分
第一部分,當DOM初始化之後,要先把對話框給隱藏起來
並且把遮罩div的透明度設成0.5
透明度設定請參照
http://hatsukiakio.blogspot.com/2009/07/jquerycss.html
$(document).ready(function(){
$("#dialog").css("display","none");
$("#msg").css("display","none");
$("#dialog").css("opacity","0.5");
});
第二部份是msg的div中,要關閉對話框的事件區動,說是關閉,也只是把dialog隱藏起來而已
function closeDialog(){
$("#dialog").css("display","none");
$("#msg").css("display","none");
}
第三部份,show出dialog,這部份比較雜一點
function showDialog(){
/*秀出對話框*/
$("#dialog").css("display","");
$("#msg").css("display","");
var _sw=document.body.clientWidth;//得到視窗寬度
var _sh=document.body.clientHeight;//得到視窗長度
if($.browser.msie)//判斷使否為IE
{
_sh-=260;
_sw-=24;
}
/*
var scrolltop;
//得到scroll的現在位置
if (document.documentElement && document.documentElement.scrollTop)
{
scrolltop=document.documentElement.scrollTop;
}
else if(document.body){
scrolltop=document.body.scrollTop;
}
*/
var w=$("#msg").width();
var h=$("#msg").height();
var _top=_sh/2-h/2+$(document).scrollTop();//更好的方法 使用jQuery解決
var _left=_sw/2-w/2;
/*設定視窗出現位置*/
$("#msg").css("top",_top+'px');
$("#msg").css("left",_left+'px');
}
要show出對話框,只要把他的display屬性從none改成空值及可
之後可以用document.body的clientWidth跟clientHeight得到視窗的大小
再來有一點也是瀏覽器的問題,IE會把上面工具列的部分也算在視窗size裡
所以要用jQuery的$.browser.msie來判斷是不是IE來做修正
最後是得到scroll的位置,一開始我是用document.documentElement去取得
但是後來發現jQuery的+$(document).scrollTop()就能做到相同的事情了
訂閱:
文章 (Atom)