在學python的過程中,一直弄不明白sys.argv[]的意思,雖知道是表示命令行參數,但還是有些稀里糊涂的感覺。

          今天又好好學習了一把,總算是大徹大悟了。

          Sys.argv[]是用來獲取命令行參數的,sys.argv[0]表示代碼本身文件路徑,所以參數從1開始,以下兩個例子說明:

          1、使用sys.argv[]的一簡單實例,

          import sys,os
          os.system(sys.argv[1])

          這個例子os.system接收命令行參數,運行參數指令,保存為sample1.py,命令行帶參數運行sample1.py notepad,將打開記事本程序。

          2這個例子是簡明python教程上的,明白它之后你就明白sys.argv[]了。

          import sys
          def readfile(filename):  #從文件中讀出文件內容
          '''Print a file to the standard output.'''
          f = file(filename)
          while True:
          line = f.readline()
          if len(line) == 0:
          break
          print line, # notice comma  分別輸出每行內容
          f.close()
          # Script starts from here
          if len(sys.argv) < 2:
          print 'No action specified.'
          sys.exit()
          if sys.argv[1].startswith('--'):
          option = sys.argv[1][2:]
          # fetch sys.argv[1] but without the first two characters
          if option == 'version'#當命令行參數為-- version,顯示版本號
          print 'Version 1.2'
          elif option == 'help'#當命令行參數為--help時,顯示相關幫助內容
          print '''"
          This program prints files to the standard output.
          Any number of files can be specified.
          Options include:
          --version : Prints the version number
          --help    : Display this help'''
          else:
          print 'Unknown option.'
          sys.exit()
          else:
          for filename in sys.argv[1:]: #當參數為文件名時,傳入readfile,讀出其內容
          readfile(filename)

           

          保存程序為sample.py.我們驗證一下:

          命令行帶參數運行:sample.py –version 輸出結果為:version 1.2

          命令行帶參數運行:sample.py –help 輸出結果為:This program prints files……

          在與sample.py同一目錄下,新建a.txt的記事本文件,內容為:test argv;命令行帶參數運行:sample.py a.txt,輸出結果為a.txt文件內容:test argv,這里也可多帶幾個參數,程序會先后輸出參數文件內容。

          posted @ 2009-03-23 16:43 小馬歌 閱讀(961) | 評論 (0)編輯 收藏
           
          提出解決辦法的是微軟某個MVP工程師,方法是在注冊表添加某個鍵值:
          在HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main添加DWORD項RunOnceHasShown,RunOnceComplete并修改成1!
          行是行,但是沒開啟CLEARTYPE,而且每次新建標簽都要彈到about:tabs那去
          posted @ 2009-03-23 10:26 小馬歌 閱讀(192) | 評論 (0)編輯 收藏
           


          php include_path設置
          2008-12-25 10:16

          一般情況下,我們設置php的include_path都會通過修改php.ini來實現。
          有時候,我們沒有服務器的權限。有時候,我們把一個目錄加到include_path會讓已有的程序沖突。受cakephp的啟發:在app/webroot目錄下index.php有如下代碼
          ini_set('include_path', CAKE_CORE_INCLUDE_PATH . PATH_SEPARATOR . ROOT . DS . APP_DIR . DS . PATH_SEPARATOR . ini_get('include_path'));
          我們看到這個程序動態修改include_path。不過cake在這兒是把 CAKE_CORE_INCLUDE_PATH 和 APP_DIR 加到 include_path里,并且優先在這兩個目錄下找包含程序。
          注意到它這里用到了PATH_SEPARATOR這個變量。這樣這段代碼在windows和linux下能通用。

          從中受到啟發,我們可以根據自己的需要把一些include目錄動態的加入進來。比如說我們有很多libs:lib1,lib2,lib3等等。我們不必把這些libs都加到include_path里,因為它們之間可能沖突。
          可以建立一個inc_dir,并把這個目錄加入到include_path。在inc_dir下,分別建立inc_path1.php inc_path2.php inc_path3.php
          分別寫入
          <?php
          ini_set('include_path', ini_get('include_path').PATH_SEPARATOR.$dirToLib1);
          <?php
          ini_set('include_path', ini_get('include_path').PATH_SEPARATOR.$dirToLib2);
          <?php
          ini_set('include_path', ini_get('include_path').PATH_SEPARATOR.$dirToLib3);

          在寫程序的時候,比如要用lib2的functions.php
          就可以這么寫
          <?php
          require 'inc_path2.php';
          require 'functions.php';
          //....

          來源:http://hi.baidu.com/_doc/blog/item/f3135fdf16b38e16495403a7.html

          posted @ 2009-03-20 10:34 小馬歌 閱讀(1151) | 評論 (0)編輯 收藏
           

          from:http://huaidan.org/archives/2085.html

          一、驗證碼的基本知識

          1. 驗證碼的主要目的是強制人機交互來抵御機器自動化攻擊的。

          2. 大部分的驗證碼設計者并不得要領,不了解圖像處理,機器視覺,模式識別,人工智能的基本概念。

          3. 利用驗證碼,可以發財,當然要犯罪:比如招商銀行密碼只有6位,驗證碼形同虛設,計算機很快就能破解一個有錢的賬戶,很多帳戶是可以網上交易的。

          4. 也有設計的比較好的,比如Yahoo,Google,Microsoft等。而國內Tencent的中文驗證碼雖然難,但算不上好。

          二、人工智能,模式識別,機器視覺,圖像處理的基本知識

          1)主要流程:

          比如我們要從一副圖片中,識別出驗證碼;比如我們要從一副圖片中,檢測并識別出一張人臉。 大概有哪些步驟呢?

          1.圖像采集:驗證碼呢,就直接通過HTTP抓HTML,然后分析出圖片的url,然后下載保存就可以了。 如果是人臉檢測識別,一般要通過視屏采集設備,采集回來,通過A/D轉操作,存為數字圖片或者視頻頻。

          2.預處理:檢測是正確的圖像格式,轉換到合適的格式,壓縮,剪切出ROI,去除噪音,灰度化,轉換色彩空間這些。

          3.檢測:車牌檢測識別系統要先找到車牌的大概位置,人臉檢測系統要找出圖片中所有的人臉(包括疑似人臉);驗證碼識別呢,主要是找出文字所在的主要區域。

          4.前處理:人臉檢測和識別,會對人臉在識別前作一些校正,比如面內面外的旋轉,扭曲等。我這里的驗證碼識別,“一般”要做文字的切割

          5.訓練:通過各種模式識別,機器學習算法,來挑選和訓練合適數量的訓練集。不是訓練的樣本越多越好。過學習,泛化能力差的問題可能在這里出現。這一步不是必須的,有些識別算法是不需要訓練的。

          6.識別:輸入待識別的處理后的圖片,轉換成分類器需要的輸入格式,然后通過輸出的類和置信度,來判斷大概可能是哪個字母。識別本質上就是分類。

          2)關鍵概念:

          圖像處理:一般指針對數字圖像的某種數學處理。比如投影,鈍化,銳化,細化,邊緣檢測,二值化,壓縮,各種數據變換等等。

          1.二值化:一般圖片都是彩色的,按照逼真程度,可能很多級別。為了降低計算復雜度,方便后續的處理,如果在不損失關鍵信息的情況下,能將圖片處理成黑白兩種顏色,那就最好不過了。

          2.細化:找出圖像的骨架,圖像線條可能是很寬的,通過細化將寬度將為1,某些地方可能大于1。不同的細化算法,可能有不同的差異,比如是否更靠近線條中間,比如是否保持聯通行等。

          3.邊緣檢測:主要是理解邊緣的概念。邊緣實際上是圖像中圖像像素屬性變化劇烈的地方。可能通過一個固定的門限值來判斷,也可能是自適應的。門限可能是圖像全局的,也可能是局部的。不能說那個就一定好,不過大部分時候,自適應的局部的門限可能要好點。被分析的,可能是顏色,也可能是灰度圖像的灰度。

          機器視覺:利用計算機來模式實現人的視覺。 比如物體檢測,定位,識別。按照對圖像理解的層次的差別,分高階和低階的理解。

          模式識別:對事物或者現象的某種表示方式(數值,文字,我們這里主要想說的是數值),通過一些處理和分析,來描述,歸類,理解,解釋這些事物,現象及其某種抽象。

          人工智能:這種概念比較寬,上面這些都屬于人工智能這個大的方向。簡單點不要過分學院派的理解就是,把人類的很“智能”的東西給模擬出來協助生物的人來處理問題,特別是在計算機里面。

          三、常見的驗證碼的破解分析

          以http://libcaca.zoy.org/wiki/PWNtcha這里PWNtcha項目中的資料為例分析,各種驗證碼的破解。(方法很多,僅僅從我個人乍看之下覺得可行的方法來分析)

          1)Authimage


          使用的反破解技巧:

          1.不連續的點組成字符
          2.有一定程度的傾斜

          設計不好的地方:

          1.通過縱橫的直方圖投影,可以找到字幕區域
          2.通過Hough變換,適當的參數,可以找到近似的橫線,可以做傾斜矯正
          3.字符串的傾斜式面內的,沒有太多的破解難度
          4.字母寬度一定,大小一定

          2)Clubic


          使用的反破解技巧:

          1.字符是手寫體

          設計不好的地方:

          1.檢測切割階段沒有任何技術含量,屬于設計的比較丑的
          2.只有數字,而且手寫體變化不大
          3.表面看起來對識別階段有難度,仔細分析,發現幾乎不用任何高級的訓練識別算法,就固定的招某些像素點是否有色彩就夠了

          3)linuxfr.org


          使用的反破解技巧:

          1.背景顏色塊
          2.前景的橫線或矩形

          設計不好的地方:

          1.背景色是單一色塊,有形狀,通過Region-Growth區域增長來很容易把背景給去掉
          2.前景色是標準的線條,色彩單一
          3.字母無粘連
          4.都是印刷體

          4)Ourcolony


          使用的反破解技巧:

          1.設計的太低級,不屑于去評價

          設計不好的地方:

          1.這種驗證碼,設計的最丑,但還是能把菜鳥搞定,畢竟學計算機的少,搞這個破解的更少,正所謂隔行如隔山

          5)LiveJournal


          使用的反破解技巧:

          1.這個設計略微好點,使用個隨機噪音,而且作為前景
          2.字母位置粗細都有變化

          設計不好的地方:

          1.字母沒有粘連
          2.噪音類型單一
          3.通過在X軸的直方圖投影,能準確分割字幕
          4.然后在Y周作直方圖投影,能準確定位高度
          5.識別階段,都是印刷體,簡單地很

          四、網上的一些高級驗證碼

          1)ICQ


          2)IMDb


          3)MS MVPS

          4)MVN Forum

          這些類型是被很多人認為比較難得類型,分析一下可以發現,字符檢測,定位和分割都不是難。 唯一影響識別率的是IMDBb和MVPS這兩類,字體變形略大。

          總體來說,這些類型的破解也不難,很容易做到50%以上的識別率。

          五、高級驗證碼的破解分析

          時間關系,我簡單介紹如何利用圖像處理和模式識別技術,自動識別比較高級的驗證碼。
          (以風頭正勁的Google為例)


          1)至少從目前的AI的發展程度看,沒有簡單的做法能自動處理各種不同的驗證碼,即使能力很強,那么系統自然也十分復雜強大。所以,要想在很簡單的算法實現比較高級的驗證碼破解,必須分析不同驗證碼算法的特點:

          作為一般的圖像處理和計算機視覺,會考慮色彩,紋理,形狀等直接的特征,同時也考慮直方圖,灰度等統計特征,還考慮FFT,Wavelet等各種變換后的特征。但最終目標都是Dimension Reduction(降維)然后利于識別,不僅僅是速度的考慮。從圖像的角度看,很多系統都考慮轉換為灰度級甚者黑白圖片。
           
          Google的圖片可以看出,顏色變化是虛晃一槍,不存在任何處理難度。難度是字體變形和字符粘連。
           
          如果能成功的分割字符,那么后期識別無論是用SVM等分類算法,還是分析筆順比劃走向來硬識別,都相對好做。
           
          2)圖像處理和粘連分割

          代碼中的part1目錄主要完成圖像預處理和粘連字符分割
          001:將圖像從jpg等格式轉換為位圖便于處理
          002:采用Fix/Adaptive的Threshold門限算法,將圖片Bin-Value二值化。
          (可用003算法)
          003:采用OSTU分水嶺算法,將圖片Bin-Value二值化。
          (更通用,大部分時候效果更好)
          005:獲取ROI感興趣的區域。
          006:Edge Trace邊緣跟蹤。
          007:Edge Detection邊界檢測。
          008:Thin細化去骨架。
          009:做了一些Tidy整理。
            (這個一般要根據特定的Captcha算法調整)
          010:做切割,注意圖片中紅色的交叉點。
          011:將邊緣檢測和骨干交叉點監測的圖像合并。
            (合并過程可以做分析: 比如X坐標偏移門限分析,交叉點區域紋理分析,線條走勢分析,等等各種方法,找出更可能的切分點和分離后部件的組合管理。)


          代碼:(代碼質量不高,從其他項目拷貝過來,簡單修改的。)

          查看代碼(./pstzine_09_01.txt)

          注: 在這里,我們可以看到,基本的部件(字母是分割開了,但可以造成統一字母的被切割成多個Component。 一種做法是:利用先驗知識,做分割; 另外一種做法是,和第二部分的識別結合起來。 比如按照從左至右,嘗試增加component來識別,如果不能識別而且component的總寬度,總面積還比較小,繼續增加。 當然不排除拒識的可能性。 )

          3)字符部件組合和識別。

          part2的代碼展示了切割后的字母組合,和基于svm的字符識別的訓練和識別過程。Detection.cpp中展示了ImageSpam檢測過程中的一些字符分割和組合,layout的分析和利用的簡單技術。 而Google的驗證碼的識別,完全可以不用到,僅做參考。

          SVM及使用:

          本質上,SVM是一個分類器,原始的SVM是一個兩類分類的分類器。可以通過1:1或者1:n的方式來組合成一個多類分類的分類器。 天生通過核函數的使用支持高維數據的分類。從幾何意義上講,就是找到最能表示類別特征的那些向量(支持向量SV),然后找到一條線,能最大化分類的Margin。

          libSVM是一個不錯的實現。

          訓練間斷和識別階段的數據整理和歸一化是一樣的。 這里的簡單做法是:

          首先:

          #define SVM_MAX +0.999
          #define SVM_MIN +0.001

          其次:

          掃描黑白待識別字幕圖片的每個像素,如果為0(黑色,是字母上的像素),那么svm中該位置就SVM_MAX,反之則反。

          最后:

          訓練階段,在svm的input的前面,為該類打上標記,即是那一個字母。
          識別階段,當然這個類別標記是SVM分類出來。

          注意:

          如果是SVM菜鳥,最好找一個在SVM外邊做了包裝的工具,比如樣本選擇,交叉驗證,核函數選擇這些,讓程序自動選擇和分析。

          代碼:通過ReginGrowth來提取單個單個的字符,然后開始識別。

          查看代碼(./pstzine_09_02.txt)

          六、對驗證碼設計的一些建議

          1.在噪音等類型的使用上,盡力讓字符和用來混淆的前景和背景不容易區分。盡力讓壞人(噪音)長得和好人(字母)一樣。

          2.特別好的驗證碼的設計,要盡力發揮人類擅長而AI算法不擅長的。 比如粘連字符的分割和手寫體(通過印刷體做特別的變形也可以)。 而不要一味的去加一些看起來比較復雜的噪音或者其他的花哨的東西。即使你做的足夠復雜,但如果人也難識別,顯然別人認為你是沒事找抽型的。

          3. 從專業的機器視覺的角度說,驗證碼的設計,一定要讓破解者在識別階段,反復在低階視覺和高階視覺之間多反復幾次才能識別出來。 這樣可以大大降低破解難度和破解的準確率。

          七、個人鄭重申明

          1.這個問題,本身是人工智能,計算機視覺,模式識別領域的一個難題。我是蝦米,菜得不能再菜的那種。作為破解者來說,是出于劣勢地位。要做的很好,是很難得。總體來說,我走的是比較學院派的線路,能真正的破解難度比較高的驗證碼,不同于網上很多不太入流的破解方法。我能做的只有利用有限的知識,拋磚引玉而已。 很多OCR的技術,特別是離線手寫體中文等文字識別的技術,個人了解有限的很,都不敢在這里亂寫。

          2.希望不要把這種技術用于非法用途。

          posted @ 2009-03-14 09:54 小馬歌 閱讀(592) | 評論 (0)編輯 收藏
           

          [轉自:http://www.dotcomunderground.com/blogs/2006/09/02/gws21-google-web-server/ ]

          Google Web Server

          www.google.com的頭信息如下:

          URL: http://www.google.com/
          HTTP Header:
          Status: HTTP/1.0 200 OK
          Cache-Control: private
          Content-Type: text/html
          Set-Cookie: PREF=ID=90107988a9ae4a88:TM=1157210262:LM=1157210262:S=ltFJ-O9yIsDIPVaS; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
          Server: GWS/2.1
          Content-Length: 0
          Date: Sat, 02 Sep 2006 15:17:42 GMT
          Connection: Keep-Alive

          List of Google Server Types - Services and Server Software used by Google
          Main Search: GWS/2.1
          Google Accounts: GFE/1.3*
          Google AdSense: GFE/1.3*
          Google AdWords: GFE/1.3*
          Google Analytics (Login Page): GWS/2.1
          Google Analytics (Auth Page): GFE/1.3*
          Google Analytics (Other Pages): ucfe*
          Google Analytics (Analysis Image and JS): ucfe
          Google Analytics (Images/JS/CSS/Flash): ga-reporting-fe
          Google Answers: GFE/1.3
          Google Base: asfe
          Blogger: Apache
          Google Book Search: OFE/0.1
          Google Calendar: GFE/1.3
          Google Catalogs: OFE/0.1
          Google Code: codesite/2104877
          Google Desktop: GFE/1.3
          Google Directory: GWS/2.1
          Google Downloads: GWS/2.1
          Google Finance: SFE/0.8
          Google Finance Stock Charts (Images): FTS (C)1997-2006 IS.Teledata AG
          Froogle: cffe
          Google Groups: GWS-GRFE/0.50
          Hello: Apache/2.0.53
          Google Help Pages: TrakhelpServer/1.0a
          Google Images: GWS/2.1
          Google Labs: Apache
          Google Local / Maps: mfe
          Google Local/Maps (Images): tfe
          Google Mail: GWS/2.1
          Google Mobile: GWS/2.1
          Google Moon: mfe
          Google Moon (Images): GWS/2.1
          Google Music Search: mws
          Google News: NFE/1.0
          Orkut: GFE/1.3*
          Google Pack: COMINST/1.0
          Picasa (.com): Apache/2.0.53
          Picasa (.google.com): GWS/2.1
          Google Page Creator (Sign-up page): GFE/1.3*
          Google Page Creator (User pages): GFE/1.3
          Google Personalized Homepage: igfe
          Google Scholar: GWS/2.1
          Google Search History: Search-History HTTP Server
          Google Sets: Apache
          Google Site-Flavored: GWS/2.1
          Google Sitemaps: GFE/1.3
          Google SMS: GWS/2.1
          Google SMS Search Requests: SMPP server 1.0
          Google SMS (GMail Registration): GFE/1.3*
          Google SMS (Page Viewer): GFE/1.3
          Google Suggest: Auto-Completion Server
          Google Transit: mfe
          Google Translate: TWS/0.9
          Google Video: GFE/1.3
          Google Reader: GFE/1.3
          Google Ride Finder: Apache
          Google Talk: GWS/2.1
          Google Toolbar: GFE/1.3
          Google Toolbar (PR Lookup): GWS/2.1
          Google Web Accelerator: GFE/1.3
          Google Web Alerts: PSFE/4.0

          Blogger and Google Labs also gives a little diffrent “HTTP Header” reply than usual Apache gives. (version number missing).

          Please do share if you know more about GWS

          posted @ 2009-03-10 19:35 小馬歌 閱讀(694) | 評論 (1)編輯 收藏
           
          April 24th, 2008

          今天無意中看到老王的技術手冊中對 unicode 字符串的轉換方法。

          才想起以前自己做的一個轉換程序時,也碰到過這樣的問題,幾乎被遺忘了。避免忘記,與大家分享一下這兩種方法。

          老王掘出來的被遺忘的mb_convert_encoding方法:mb_convert_encoding(’醉爱’, ‘UTF-8′, ‘HTML-ENTITIES’);

          我以前做的一個方法,對比上面的來說,很笨。不過在沒有 mb 擴展的時候還是可以參考一下的。

          function unescape($str){
          $str = rawurldecode($str);
          preg_match_all(”/&#(\d+);/U”,$str,$r);
          $arr = $r[1];
          $cstr = array();
          foreach($arr as $number){
          $cstr[] = iconv(”UCS-2″,”GBK”,pack(”n”,$number));
          }
          return join(”",$cstr);
          }

          unescape(’醉爱’);

          posted @ 2009-03-10 19:31 小馬歌 閱讀(315) | 評論 (0)編輯 收藏
           
          javascript:var%20a=document.all;for(var%20i=0;i<a.length;i++){a[i].onclick=function(){alert(this.innerHTML);event.cancelBubble=true;return%20false;};a[i].onmouseover=function(){this.style.border="1px%20solid%20#261CDC";event.cancelBubble=true;};a[i].onmouseout=function(){this.style.border="none";}};void(0);



          把這段代碼作為一個地址保存到收藏夾,想看哪個網頁時,點一下 收藏夾的這個按鈕,就可以了。
          posted @ 2009-03-10 19:29 小馬歌 閱讀(111) | 評論 (0)編輯 收藏
           
          from:http://www.php5x.com/

          英文版權歸Reinhold Weber所有,中譯文作者yangyang(aka davidkoree)。雙語版可用于非商業傳播,但須注明英文版作者、版權信息,以及中譯文作者。翻譯水平有限,請廣大PHPer指正。

          1.如果一個方法可靜態化,就對它做靜態聲明。速率可提升至4倍。

          2.echo 比 print 快。

          3.使用echo的多重參數(譯注:指用逗號而不是句點)代替字符串連接。

          4.在執行for循環之前確定最大循環數,不要每循環一次都計算最大值。

          5.注銷那些不用的變量尤其是大數組,以便釋放內存。

          6.盡量避免使用__get,__set,__autoload。

          7.require_once()代價昂貴。

          8.在包含文件時使用完整路徑,解析操作系統路徑所需的時間會更少。

          9.如果你想知道腳本開始執行(譯注:即服務器端收到客戶端請求)的時刻,使用$_SERVER[‘REQUEST_TIME’]要好于time()。

          10.函數代替正則表達式完成相同功能。

          11.str_replace函數比preg_replace函數快,但strtr函數的效率是str_replace函數的四倍。

          12.如果一個字符串替換函數,可接受數組或字符作為參數,并且參數長度不太長,那么可以考慮額外寫一段替換代碼,使得每次傳遞參數是一個字符,而不是只寫一行代碼接受數組作為查詢和替換的參數。

          13.使用選擇分支語句(譯注:即switch case)好于使用多個if,else if語句。

          14.用@屏蔽錯誤消息的做法非常低效。

          15.打開apache的mod_deflate模塊。

          16.數據庫連接當使用完畢時應關掉。

          17.$row[‘id’]的效率是$row[id]的7倍。

          18.錯誤消息代價昂貴。

          19.盡量不要在for循環中使用函數,比如for ($x=0; $x < count($array); $x)每循環一次都會調用count()函數。

          20.在方法中遞增局部變量,速度是最快的。幾乎與在函數中調用局部變量的速度相當。

          21.遞增一個全局變量要比遞增一個局部變量慢2倍。

          22.遞增一個對象屬性(如:$this->prop++)要比遞增一個局部變量慢3倍。

          23.遞增一個未預定義的局部變量要比遞增一個預定義的局部變量慢9至10倍。

          24.僅定義一個局部變量而沒在函數中調用它,同樣會減慢速度(其程度相當于遞增一個局部變量)。PHP大概會檢查看是否存在全局變量。

          25.方法調用看來與類中定義的方法的數量無關,因為我(在測試方法之前和之后都)添加了10個方法,但性能上沒有變化。

          26.派生類中的方法運行起來要快于在基類中定義的同樣的方法。

          27.調用帶有一個參數的空函數,其花費的時間相當于執行7至8次的局部變量遞增操作。類似的方法調用所花費的時間接近于15次的局部變量遞增操作。

          28.用單引號代替雙引號來包含字符串,這樣做會更快一些。因為PHP會在雙引號包圍的字符串中搜尋變量,單引號則不會。當然,只有當你不需要在字符串中包含變量時才可以這么做。

          29.輸出多個字符串時,用逗號代替句點來分隔字符串,速度更快。注意:只有echo能這么做,它是一種可以把多個字符串當作參數的“函數”(譯注:PHP手冊中說echo是語言結構,不是真正的函數,故把函數加上了雙引號)。

          30.Apache解析一個PHP腳本的時間要比解析一個靜態HTML頁面慢2至10倍。盡量多用靜態HTML頁面,少用腳本。

          31.除非腳本可以緩存,否則每次調用時都會重新編譯一次。引入一套PHP緩存機制通常可以提升25%至100%的性能,以免除編譯開銷。

          32.盡量做緩存,可使用memcached。memcached是一款高性能的內存對象緩存系統,可用來加速動態Web應用程序,減輕數據庫負載。對運算碼 (OP code)的緩存很有用,使得腳本不必為每個請求做重新編譯。

          33.當操作字符串并需要檢驗其長度是否滿足某種要求時,你想當然地會使用strlen()函數。此函數執行起來相當快,因為它不做任何計算,只返回在 zval 結構(C的內置數據結構,用于存儲PHP變量)中存儲的已知字符串長度。但是,由于strlen()是函數,多多少少會有些慢,因為函數調用會經過諸多步 驟,如字母小寫化(譯注:指函數名小寫化,PHP不區分函數名大小寫)、哈希查找,會跟隨被調用的函數一起執行。在某些情況下,你可以使用isset() 技巧加速執行你的代碼。

          (舉例如下)
          if (strlen($foo) < 5) { echo “Foo is too short”$$ }
          (與下面的技巧做比較)
          if (!isset($foo{5})) { echo “Foo is too short”$$ }

          調用isset()恰巧比strlen()快,因為與后者不同的是,isset()作為一種語言結構,意味著它的執行不需要函數查找和字母小寫化。也就是說,實際上在檢驗字符串長度的頂層代碼中你沒有花太多開銷。

          34.當執行變量$i的遞增或遞減時,$i++會比++$i慢一些。這種差異是PHP特有的,并不適用于其他語言,所以請不要修改你的C或Java代碼并 指望它們能立即變快,沒用的。++$i更快是因為它只需要3條指令(opcodes),$i++則需要4條指令。后置遞增實際上會產生一個臨時變量,這個 臨時變量隨后被遞增。而前置遞增直接在原值上遞增。這是最優化處理的一種,正如Zend的PHP優化器所作的那樣。牢記這個優化處理不失為一個好主意,因為并不是所有的指令優化器都會做同樣的優化處理,并且存在大量沒有裝配指令優化器的互聯網服務提供商(ISPs)和服務器。

          35.并不是事必面向對象(OOP),面向對象往往開銷很大,每個方法和對象調用都會消耗很多內存。

          36.并非要用類實現所有的數據結構,數組也很有用。

          37.不要把方法細分得過多,仔細想想你真正打算重用的是哪些代碼?

          38.當你需要時,你總能把代碼分解成方法。

          39.盡量采用大量的PHP內置函數。

          40.如果在代碼中存在大量耗時的函數,你可以考慮用C擴展的方式實現它們。

          41.評估檢驗(profile)你的代碼。檢驗器會告訴你,代碼的哪些部分消耗了多少時間。Xdebug調試器包含了檢驗程序,評估檢驗總體上可以顯示出代碼的瓶頸。

          42.mod_zip可作為Apache模塊,用來即時壓縮你的數據,并可讓數據傳輸量降低80%。

          posted @ 2009-03-10 16:13 小馬歌 閱讀(93) | 評論 (0)編輯 收藏
           
          用操作符"@"獲取操作執行的句柄,然后判斷這個句柄的boolean值。如果發生問題,自己拋出Exception.
          比如下面一個解析xml可能遇到的運行時異常:
          try{
           $doc = new DOMDocument();
           $aa = @$doc->load('C:/cinema_data.xml');
           echo $aa;
           if(!$aa){
            throw  new Exception('ocur excep');
           }
           echo 'ccc';
          }catch(Exception $e){
           //echo $e->getTrace();
           echo 'bbb';
           exit;
          }

          可以看到,發生異常時,echo 'ccc'是沒執行的。
          posted @ 2009-03-10 16:08 小馬歌 閱讀(271) | 評論 (0)編輯 收藏
           

          使用 DOM 庫、SAX 解析器和正則表達式

          developerWorks
          文檔選項

          級別: 中級

          Jack Herrington (jack_d_herrington@codegeneration.net), 高級軟件工程師, "Code Generation Network"

          2006 年 2 月 06 日

          有許多技術可用于用 PHP 讀取和編寫 XML。本文提供了三種方法讀取 XML:使用 DOM 庫、使用 SAX 解析器和使用正則表達式。還介紹了使用 DOM 和 PHP 文本模板編寫 XML。

          用 PHP 讀取和編寫可擴展標記語言(XML)看起來可能有點恐怖。實際上,XML 和它的所有相關技術可能是恐怖的,但是用 PHP 讀取和編寫 XML 不一定是項恐怖的任務。首先,需要學習一點關于 XML 的知識 —— 它是什么,用它做什么。然后,需要學習如何用 PHP 讀取和編寫 XML,而有許多種方式可以做這件事。

          本文提供了 XML 的簡短入門,然后解釋如何用 PHP 讀取和編寫 XML。

          什么是 XML?

          XML 是一種數據存儲格式。它沒有定義保存什么數據,也沒有定義數據的格式。XML 只是定義了標記和這些標記的屬性。格式良好的 XML 標記看起來像這樣:

          <name>Jack Herrington</name>

          這個 <name> 標記包含一些文本:Jack Herrington。

          不包含文本的 XML 標記看起來像這樣:

          <powerUp />

          用 XML 對某件事進行編寫的方式不止一種。例如,這個標記形成的輸出與前一個標記相同:

          <powerUp></powerUp>

          也可以向 XML 標記添加屬性。例如,這個 <name> 標記包含 firstlast 屬性:

          <name first="Jack" last="Herrington" />

          也可以用 XML 對特殊字符進行編碼。例如,& 符號可以像這樣編碼:

          &

          包含標記和屬性的 XML 文件如果像示例一樣格式化,就是格式良好的,這意味著標記是對稱的,字符的編碼正確。清單 1 是一份格式良好的 XML 的示例。


          清單 1. XML 圖書列表示例
            <books>
                                  <book>
                                  <author>Jack Herrington</author>
                                  <title>PHP Hacks</title>
                                  <publisher>O'Reilly</publisher>
                                  </book>
                                  <book>
                                  <author>Jack Herrington</author>
                                  <title>Podcasting Hacks</title>
                                  <publisher>O'Reilly</publisher>
                                  </book>
                                  </books>
                                  

          清單 1 中的 XML 包含一個圖書列表。父標記 <books> 包含一組 <book> 標記,每個 <book> 標記又包含 <author><title><publisher> 標記。

          當 XML 文檔的標記結構和內容得到外部模式文件的驗證后,XML 文檔就是正確的。模式文件可以用不同的格式指定。對于本文來說,所需要的只是格式良好的 XML。

          如果覺得 XML 看起來很像超文本標記語言(HTML),那么就對了。XML 和 HTML 都是基于標記的語言,它們有許多相似之處。但是,要著重指出的是:雖然 XML 文檔可能是格式良好的 HTML,但不是所有的 HTML 文檔都是格式良好的 XML。換行標記(br)是 XML 和 HTML 之間區別的一個好例子。這個換行標記是格式良好的 HTML,但不是格式良好的 XML:

          <p>This is a paragraph<br>
          With a line break</p>

          這個換行標記是格式良好的 XML 和 HTML:

          <p>This is a paragraph<br />
          With a line break</p>

          如果要把 HTML 編寫成同樣是格式良好的 XML,請遵循 W3C 委員會的可擴展超文本標記語言(XHTML)標準(參見 參考資料)。所有現代的瀏覽器都能呈現 XHTML。而且,還可以用 XML 工具讀取 XHTML 并找出文檔中的數據,這比解析 HTML 容易得多。





          回頁首


          使用 DOM 庫讀取 XML

          讀取格式良好的 XML 文件最容易的方式是使用編譯成某些 PHP 安裝的文檔對象模型 (DOM)庫。DOM 庫把整個 XML 文檔讀入內存,并用節點樹表示它,如圖 1 所示。


          圖 1. 圖書 XML 的 XML DOM 樹
          圖書 XML 的 XML DOM 樹

          樹頂部的 books 節點有兩個 book 子標記。在每本書中,有 authorpublishertitle 幾個節點。authorpublishertitle 節點分別有包含文本的文本子節點。

          讀取圖書 XML 文件并用 DOM 顯示內容的代碼如清單 2 所示。


          清單 2. 用 DOM 讀取圖書 XML
            <?php
                                  $doc = new DOMDocument();
                                  $doc->load( 'books.xml' );
                                  $books = $doc->getElementsByTagName( "book" );
                                  foreach( $books as $book )
                                  {
                                  $authors = $book->getElementsByTagName( "author" );
                                  $author = $authors->item(0)->nodeValue;
                                  $publishers = $book->getElementsByTagName( "publisher" );
                                  $publisher = $publishers->item(0)->nodeValue;
                                  $titles = $book->getElementsByTagName( "title" );
                                  $title = $titles->item(0)->nodeValue;
                                  echo "$title - $author - $publisher\n";
                                  }
                                  ?>
                                  

          腳本首先創建一個 new DOMdocument 對象,用 load 方法把圖書 XML 裝入這個對象。之后,腳本用 getElementsByName 方法得到指定名稱下的所有元素的列表。

          book 節點的循環中,腳本用 getElementsByName 方法獲得 authorpublishertitle 標記的 nodeValuenodeValue 是節點中的文本。腳本然后顯示這些值。

          可以在命令行上像這樣運行 PHP 腳本:

          % php e1.php
          PHP Hacks - Jack Herrington - O'Reilly
          Podcasting Hacks - Jack Herrington - O'Reilly
          %

          可以看到,每個圖書塊輸出一行。這是一個良好的開始。但是,如果不能訪問 XML DOM 庫該怎么辦?





          回頁首


          用 SAX 解析器讀取 XML

          讀取 XML 的另一種方法是使用 XML Simple API(SAX)解析器。PHP 的大多數安裝都包含 SAX 解析器。SAX 解析器運行在回調模型上。每次打開或關閉一個標記時,或者每次解析器看到文本時,就用節點或文本的信息回調用戶定義的函數。

          SAX 解析器的優點是,它是真正輕量級的。解析器不會在內存中長期保持內容,所以可以用于非常巨大的文件。缺點是編寫 SAX 解析器回調是件非常麻煩的事。清單 3 顯示了使用 SAX 讀取圖書 XML 文件并顯示內容的代碼。


          清單 3. 用 SAX 解析器讀取圖書 XML
            <?php
                                  $g_books = array();
                                  $g_elem = null;
                                  function startElement( $parser, $name, $attrs )
                                  {
                                  global $g_books, $g_elem;
                                  if ( $name == 'BOOK' ) $g_books []= array();
                                  $g_elem = $name;
                                  }
                                  function endElement( $parser, $name )
                                  {
                                  global $g_elem;
                                  $g_elem = null;
                                  }
                                  function textData( $parser, $text )
                                  {
                                  global $g_books, $g_elem;
                                  if ( $g_elem == 'AUTHOR' ||
                                  $g_elem == 'PUBLISHER' ||
                                  $g_elem == 'TITLE' )
                                  {
                                  $g_books[ count( $g_books ) - 1 ][ $g_elem ] = $text;
                                  }
                                  }
                                  $parser = xml_parser_create();
                                  xml_set_element_handler( $parser, "startElement", "endElement" );
                                  xml_set_character_data_handler( $parser, "textData" );
                                  $f = fopen( 'books.xml', 'r' );
                                  while( $data = fread( $f, 4096 ) )
                                  {
                                  xml_parse( $parser, $data );
                                  }
                                  xml_parser_free( $parser );
                                  foreach( $g_books as $book )
                                  {
                                  echo $book['TITLE']." - ".$book['AUTHOR']." - ";
                                  echo $book['PUBLISHER']."\n";
                                  }
                                  ?>
                                  

          腳本首先設置 g_books 數組,它在內存中容納所有圖書和圖書信息,g_elem 變量保存腳本目前正在處理的標記的名稱。然后腳本定義回調函數。在這個示例中,回調函數是 startElementendElementtextData。在打開和關閉標記的時候,分別調用 startElementendElement 函數。在開始和結束標記之間的文本上面,調用 textData

          在這個示例中,startElement 標記查找 book 標記,在 book 數組中開始一個新元素。然后,textData 函數查看當前元素,看它是不是 publishertitleauthor 標記。如果是,函數就把當前文本放入當前圖書。

          為了讓解析繼續,腳本用 xml_parser_create 函數創建解析器。然后,設置回調句柄。之后,腳本讀取文件并把文件的大塊內容發送到解析器。在文件讀取之后,xml_parser_free 函數刪除解析器。腳本的末尾輸出 g_books 數組的內容。

          可以看到,這比編寫 DOM 的同樣功能要困難得多。如果沒有 DOM 庫也沒有 SAX 庫該怎么辦?還有替代方案么?





          回頁首


          用正則表達式解析 XML

          可以肯定,即使提到這個方法,有些工程師也會批評我,但是確實可以用正則表達式解析 XML。清單 4 顯示了使用 preg_ 函數讀取圖書文件的示例。


          清單 4. 用正則表達式讀取 XML
            <?php
                                  $xml = "";
                                  $f = fopen( 'books.xml', 'r' );
                                  while( $data = fread( $f, 4096 ) ) { $xml .= $data; }
                                  fclose( $f );
                                  preg_match_all( "/\<book\>(.*?)\<\/book\>/s",
                                  $xml, $bookblocks );
                                  foreach( $bookblocks[1] as $block )
                                  {
                                  preg_match_all( "/\<author\>(.*?)\<\/author\>/",
                                  $block, $author );
                                  preg_match_all( "/\<title\>(.*?)\<\/title\>/",
                                  $block, $title );
                                  preg_match_all( "/\<publisher\>(.*?)\<\/publisher\>/",
                                  $block, $publisher );
                                  echo( $title[1][0]." - ".$author[1][0]." - ".
                                  $publisher[1][0]."\n" );
                                  }
                                  ?>
                                  

          請注意這個代碼有多短。開始時,它把文件讀進一個大的字符串。然后用一個 regex 函數讀取每個圖書項目。最后用 foreach 循環,在每個圖書塊間循環,并提取出 author、title 和 publisher。

          那么,缺陷在哪呢?使用正則表達式代碼讀取 XML 的問題是,它并沒先進行檢查,確保 XML 的格式良好。這意味著在讀取之前,無法知道 XML 是否格式良好。而且,有些格式正確的 XML 可能與正則表達式不匹配,所以日后必須修改它們。

          我從不建議使用正則表達式讀取 XML,但是有時它是兼容性最好的方式,因為正則表達式函數總是可用的。不要用正則表達式讀取直接來自用戶的 XML,因為無法控制這類 XML 的格式或結構。應當一直用 DOM 庫或 SAX 解析器讀取來自用戶的 XML。





          回頁首


          用 DOM 編寫 XML

          讀取 XML 只是公式的一部分。該怎樣編寫 XML 呢?編寫 XML 最好的方式就是用 DOM。清單 5 顯示了 DOM 構建圖書 XML 文件的方式。


          清單 5. 用 DOM 編寫圖書 XML
            <?php
                                  $books = array();
                                  $books [] = array(
                                  'title' => 'PHP Hacks',
                                  'author' => 'Jack Herrington',
                                  'publisher' => "O'Reilly"
                                  );
                                  $books [] = array(
                                  'title' => 'Podcasting Hacks',
                                  'author' => 'Jack Herrington',
                                  'publisher' => "O'Reilly"
                                  );
                                  $doc = new DOMDocument();
                                  $doc->formatOutput = true;
                                  $r = $doc->createElement( "books" );
                                  $doc->appendChild( $r );
                                  foreach( $books as $book )
                                  {
                                  $b = $doc->createElement( "book" );
                                  $author = $doc->createElement( "author" );
                                  $author->appendChild(
                                  $doc->createTextNode( $book['author'] )
                                  );
                                  $b->appendChild( $author );
                                  $title = $doc->createElement( "title" );
                                  $title->appendChild(
                                  $doc->createTextNode( $book['title'] )
                                  );
                                  $b->appendChild( $title );
                                  $publisher = $doc->createElement( "publisher" );
                                  $publisher->appendChild(
                                  $doc->createTextNode( $book['publisher'] )
                                  );
                                  $b->appendChild( $publisher );
                                  $r->appendChild( $b );
                                  }
                                  echo $doc->saveXML();
                                  ?>
                                  

          在腳本的頂部,用一些示例圖書裝入了 books 數組。這個數據可以來自用戶也可以來自數據庫。

          示例圖書裝入之后,腳本創建一個 new DOMDocument,并把根節點 books 添加到它。然后腳本為每本書的 author、title 和 publisher 創建節點,并為每個節點添加文本節點。每個 book 節點的最后一步是重新把它添加到根節點 books

          腳本的末尾用 saveXML 方法把 XML 輸出到控制臺。(也可以用 save 方法創建一個 XML 文件。)腳本的輸出如清單 6 所示。


          清單 6. DOM 構建腳本的輸出
            % php e4.php
                                  <?xml version="1.0"?>
                                  <books>
                                  <book>
                                  <author>Jack Herrington</author>
                                  <title>PHP Hacks</title>
                                  <publisher>O'Reilly</publisher>
                                  </book>
                                  <book>
                                  <author>Jack Herrington</author>
                                  <title>Podcasting Hacks</title>
                                  <publisher>O'Reilly</publisher>
                                  </book>
                                  </books>
                                  %
                                  

          使用 DOM 的真正價值在于它創建的 XML 總是格式正確的。但是如果不能用 DOM 創建 XML 時該怎么辦?





          回頁首


          用 PHP 編寫 XML

          如果 DOM 不可用,可以用 PHP 的文本模板編寫 XML。清單 7 顯示了 PHP 如何構建圖書 XML 文件。


          清單 7. 用 PHP 編寫圖書 XML
            <?php
                                  $books = array();
                                  $books [] = array(
                                  'title' => 'PHP Hacks',
                                  'author' => 'Jack Herrington',
                                  'publisher' => "O'Reilly"
                                  );
                                  $books [] = array(
                                  'title' => 'Podcasting Hacks',
                                  'author' => 'Jack Herrington',
                                  'publisher' => "O'Reilly"
                                  );
                                  ?>
                                  <books>
                                  <?php
                                  foreach( $books as $book )
                                  {
                                  ?>
                                  <book>
                                  <title><?php echo( $book['title'] ); ?></title>
                                  <author><?php echo( $book['author'] ); ?>
                                  </author>
                                  <publisher><?php echo( $book['publisher'] ); ?>
                                  </publisher>
                                  </book>
                                  <?php
                                  }
                                  ?>
                                  </books>
                                  

          腳本的頂部與 DOM 腳本類似。腳本的底部打開 books 標記,然后在每個圖書中迭代,創建 book 標記和所有的內部 titleauthorpublisher 標記。

          這種方法的問題是對實體進行編碼。為了確保實體編碼正確,必須在每個項目上調用 htmlentities 函數,如清單 8 所示。


          清單 8. 使用 htmlentities 函數對實體編碼
                                  <books>
                                  <?php
                                  foreach( $books as $book )
                                  {
                                  $title = htmlentities( $book['title'], ENT_QUOTES );
                                  $author = htmlentities( $book['author'], ENT_QUOTES );
                                  $publisher = htmlentities( $book['publisher'], ENT_QUOTES );
                                  ?>
                                  <book>
                                  <title><?php echo( $title ); ?></title>
                                  <author><?php echo( $author ); ?> </author>
                                  <publisher><?php echo( $publisher ); ?>
                                  </publisher>
                                  </book>
                                  <?php
                                  }
                                  ?>
                                  </books>
                                  

          這就是用基本的 PHP 編寫 XML 的煩人之處。您以為自己創建了完美的 XML,但是在試圖使用數據的時候,馬上就會發現某些元素的編碼不正確。





          回頁首


          結束語

          XML 周圍總有許多夸大之處和混淆之處。但是,并不像您想像的那么難 —— 特別是在 PHP 這樣優秀的語言中。在理解并正確地實現了 XML 之后,就會發現有許多強大的工具可以使用。XPath 和 XSLT 就是這樣兩個值得研究的工具。



          參考資料

          學習

          獲得產品和技術
          • 請訪問 PHP.net,了解關于 PHP 的最新新聞、找到下載,并向其他用戶學習。

          • 了解 Expat XML Parser,這個解析器用來向 PHP 提供 SAX 解析器功能。

          • 利用 IBM 試用軟件 改造您的下一個開放源碼開發項目,可以下載也可以通過 DVD 得到。


          討論


          關于作者

           

          Jack D. Herrington 是有 20 多年經驗的高級軟件工程師。他是三本書的作者:Code Generation in ActionPodcasting Hacks 和即將發表的 PHP Hacks。他還撰寫了 30 多篇文章。

          posted @ 2009-03-09 14:43 小馬歌 閱讀(187) | 評論 (0)編輯 收藏
          僅列出標題
          共95頁: First 上一頁 69 70 71 72 73 74 75 76 77 下一頁 Last 
           
          主站蜘蛛池模板: 平谷区| 汉中市| 新泰市| 多伦县| 威远县| 临颍县| 连山| 永胜县| 新营市| 高青县| 花莲县| 漳州市| 万盛区| 峨边| 抚顺县| 石门县| 威远县| 安陆市| 利津县| 宝应县| 青阳县| 阳曲县| 博客| 万山特区| 弥渡县| 兖州市| 濉溪县| 伽师县| 龙川县| 邳州市| 河曲县| 红原县| 白城市| 广州市| 原平市| 牡丹江市| 衡阳县| 易门县| 台北县| 抚顺县| 新昌县|