2017年12月7日 星期四

VFP 的報表資料

最近,因為工作需要,必需把原來用 VFP 開發的程式,轉移成 PHP 的網頁程式。使用 VFP 設計的報表,也必須改寫成網頁,藉以輸出 PDF 檔。但是使用 PHP,能想到的解決方式,就是輸入一堆座標數字,然後,用程式在對應的位置畫表格,輸出文字或資料。要一一重新決定位置或欄位的資料,是非常累人的工作。最快的方法是把 VFP 的報表設計的資料直接撈出來,轉成程式資料,然後在 PHP 中,使用 PDF 指令,把它輸出到報表 。

還好,已經有人費心的挖掘出 VFP 報表的資料表達方式,可參見下列的討論
Is it possible to open a File .FRT/FRX in MS Excel or MS Access

VFP 報表的資料,是存在 dbf 中,只是附檔名不同而已,可以使用 USE 直接開啟,讀取其中的資料。檔案結構的說明,請參見: .FRX and .LBX Table Structure for Visual FoxPro for Windows



Crystal Report 與 pdf 的度量單位

Crystal Report 的單位為 TWIPS (twentieth of a point) [http://en.wikipedia.org/wiki/Twip], 1 twip = 1/1440 inch, they are independent of the number of pixels on the screen; to find out how many twips wide your document is, you check the page size you setup on the report (in inches let’s say, then multiply by 1440). And I’m not sure you can change this programmatically.

Anyway: if 1 inch = 1440 twips, 1 cm = 576 twips.

PDF 的單位如下,AbcPdf 也可設成 twips
This property holds the current measurement units. This property can take any of the following values:

points (PostScript Points) - 1/72 of an Inch
twips (Twentieths of a Point) - 1/20 of a PostScript Point

另外,PDF 的座標的原點在左下角,AbcPdf 可以設成由上往下。

電腦字型, 例如 14,轉換成 twips 為 14*20。

2017年11月23日 星期四

SQL 2000 的分頁

在 Laravel 中,雖然有方便的分頁功能,但必須是 SQL 2005 以上。使用 SQL 2000,就只好自行想辦法了。

下面是參考網路找來的作法,參見 Efficient Paging (Limit) Query in SQLServer 2000?

-----------------
CREATE PROCEDURE [dbo].[GetPage]
    @pTableName VARCHAR(30),
    @pColumns VARCHAR(200) = '*',
    @pFilter VARCHAR(200) = '',
    @pSort VARCHAR(200) = '',
    @pPage INT = 1,
    @pPageRows INT = 10
    AS

    SET NOCOUNT ON
    DECLARE @vSQL VARCHAR(4000)
    DECLARE @vTempTable VARCHAR(30)
    DECLARE @vRowStart INT
    DECLARE @vTotalRows INT

    SET @vTempTable = '##Tmp' + CAST(DATEPART(YYYY, GETDATE()) AS VARCHAR(4)) +
    CAST(DATEPART(MM, GETDATE()) AS VARCHAR(2)) +
    CAST(DATEPART(DD, GETDATE()) AS VARCHAR(2)) +
    CAST(DATEPART(HH, GETDATE()) AS VARCHAR(2)) +
    CAST(DATEPART(MI, GETDATE()) AS VARCHAR(2)) +
    CAST(DATEPART(SS, GETDATE()) AS VARCHAR(2)) +
    CAST(DATEPART(MS, GETDATE()) AS VARCHAR(3))

    SET @vSQL = 'SELECT ' + @pColumns + ', IDENTITY(INT, 1, 1) AS ROWID INTO ' + @vTempTable + ' FROM ' + @pTableName

    IF @pFilter != '' AND @pFilter IS NOT NULL
    SET @vSQL = @vSQL + ' WHERE ' + @pFilter

    IF @pSort != '' AND @pSort IS NOT NULL
    SET @vSQL = @vSQL + ' ORDER BY ' + @pSort

    EXECUTE (@vSQL)

    -- Get the total number of rows selected
    SET @vTotalRows = @@ROWCOUNT

    -- If page number = 0, set it to the first page
    IF @pPage = 0
    SET @pPage = 1

    -- If page number is beyond the last page, set page to the last page
    IF (@pPage * @pPageRows) > @vTotalRows
    BEGIN
    SET @pPage = @vTotalRows / @pPageRows
    IF (@vTotalRows % @pPageRows) != 0
    SET @pPage = @pPage + 1
    END

    SET @vRowStart = ((@pPage - 1) * @pPageRows) + 1
    SET @vSQL = 'SELECT * FROM ' + @vTempTable + ' WHERE ROWID BETWEEN ' + CAST(@vRowStart AS VARCHAR(10)) +
    ' AND ' + CAST((@vRowStart + @pPageRows - 1) AS VARCHAR(10)) + ' ORDER BY ROWID'
    EXECUTE (@vSQL)

    SET @vSQL = 'DROP TABLE ' + @vTempTable
    EXECUTE (@vSQL)

GO
------------------

使用
exec getpage 'ifcrfct', '*', 'ct_cono like ''9%''', 'CT_YYSE desc', 100, 10

一些變數的值
@vTempTable: ##Tmp20171124141845213
@vSQL: SELECT *, IDENTITY(INT, 1, 1) AS ROWID INTO ##Tmp20171124142153370 FROM ifcrfct WHERE ct_cono like '9%' ORDER BY CT_YYSE desc
@vSQL: SELECT * FROM ##Tmp20171124142424353 WHERE ROWID BETWEEN 1741 AND 1750 ORDER BY ROWID


方便就好,先頂著用

一事不煩二主,再加上幾行,會在第二個 result set 傳回總筆數和總頁數
----------------------
DECLARE @vTotalPages INT
SET @vTotalPages = @vTotalRows / @pPageRows
IF (@vTotalRows % @pPageRows) != 0
    SET @vTotalPages = @vTotalPages + 1
SELECT @vTotalPages AS TotalPages
-----------------------

主要的花費,是在建立 temp table。
---------------------------------
if exists (select * from dbo.sysobjects where id = object_id(N'[tmp_test]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
   drop table [tmp_test]
GO

select *, identity(int, 1, 1) as rowid into tmp_test from caucgi.tsel
--------------------------
44 萬筆,第一次 10 秒,第二次以後,約 5 秒。

2017年11月16日 星期四

Google Static Maps 的使用

Google Static Maps API 可用來將「Google 地圖」影像內嵌在網頁中,而不需要使用 JavaScript 或任何動態頁面載入功能。

原本,這個是可以不用加 app key,但於 2017 年底, Google 更改策略,必須申請 app_key,但每天使用量不超過2萬5千,是免費的,超過則必須付費。

範例如下
http://maps.googleapis.com/maps/api/staticmap?center=25.015547,121.538156&zoom=16&size=400x300&sensor=false&markers=color:red|label:C|25.015547,121.538156&key=App_key


要使用 Google map 的服務,必須先 [取得金鑰]。在啟用之後,可以 [查詢現有金鑰],點選其中的 [資訊主頁} 可以看到使用的情形。



2017年11月10日 星期五

使用 json 記錄SQL操作


參考 1: Example SQL Server TSQL Stored Procedure to produce JSON
建立 stored procedure SerializeJSON,使用方式
EXEC [dbo].[SerializeJSON] "SELECT * FROM myTable;";


參考 2: StackOverflow 的討論 Log record changes in SQL server in an audit table
 其中一則回答,提到 Pop Rivett 所提的作法

一個 Audit TABLE 應包括下列欄位
               Type CHAR(1),   // SQL 操作: U, I, D
               TableName VARCHAR(128),
               PK VARCHAR(1000),  // 不用了
               FieldName VARCHAR(128),  // 不用了
               OldValue VARCHAR(1000),  // 以 JSON 表示
               NewValue VARCHAR(1000), // 以 JSON 表示
               UpdateDate datetime,
               UserName VARCHAR(128))


Maintaining a Log of Database Changes,比較設定 trigger 或程式完成的優缺點。仔細考慮,設定 trigger 是比較省事。

2017年10月22日 星期日

Gore-Tex 外套清洗 -- 筆記

只要打上 Gore-Tex 的外套,價格都以萬元計算。雖貴,但實用,風大當風衣,兩天當雨衣,不會像雨衣,穿得滿身是汗,外面下小雨,裡面下大雨。

不過,穿了 5, 6 年下來,實在太髒了,要想一下怎麼洗,以下是網路上朋友的經驗,便宜實用。

引用: https://www.mobile01.com/topicdetail.php?f=628&t=2291013

andyssky1985 2011-08-11 01:29 的留言
不用怕洗壞,只要是手洗,拿支不要的牙刷,用"洗碗精" 1:1泡水稀釋,慢慢大範圍溫和的刷。

不建議丟洗衣機,因為那個 內層防水熱壓條,可能依廠牌不同,副著力不同,強力洗衣機會有把那個洗掉下來的風險。 (我學弟就有過例子)

我是覺得Gore-Tex外套早期的比較耐穿,雖然3層布+XCR 當初買很貴,但是我那件歐督納外套,穿了9年了,內膠條還是很穩! 除了被我摔車磨破的某些部位,其他一概不漏水! 

9年了!!! 我怎麼保養? 就是不用保養!! 防潑水處理失效? 管它的! 塑膠雨衣外表也會濕啊
反正再怎麼防潑水,雨天爬山裡面還是多少會反潮!! 反正你裡面穿的是排汗衣,放心吧!!

外套不要急著脫,保持外套內部溫度,體溫會慢慢幫你把水氣蒸乾!! 到了目的地,慢個10分鐘脫外套,之後1小時的感受度絕對不同。 (我應該來寫本書 書名叫:不要急著脫外套)

Gore-tex風雨衣,比較怕潮濕折起來悶著。 通常有這習慣的,大概3年左右防水條就部分脫落了。
如果行進間太熱、雨停了,外套脫下來披在登山背包上,讓他通風風乾,可保障你的外套壽命。

fisheries 2011-08-11 02:15   的留言
手洗+1
洗劑可用最單純成份的洗碗精或是皂絲水

2017年10月15日 星期日

Vmware 的磁碟測試

很久以來,我都是用 Linux 當 host,然後再透過 Vmware 使用 Windows OS,這樣子的環境很具彈性和穩定度。過去,我的作法,都是把整顆實體的硬碟,給 guest OS 使用。

最近,因為同時裝了兩個 Windows 7,沒辦法分享實體硬碟,只好使用虛擬硬碟。但又擔心效能會不會差太多,搜尋不到相關資料,就自己來測測看吧。

測試的應用程式,是 Visual Foxpro 的程式,是我比較重的工作之一。在沒有調整程式之前,整個跑下來,要 20 到 30 多分鐘,若是效能變慢,要多花一倍的時間,那一定是受不了的。

Physical disk: (原來使用整顆硬碟)
1. 78.440 秒
2. 77.190 秒
3. 76.360 秒

Virtual disk,multiple file (虛擬硬碟,切成多個 2GB 的檔)
1. 76.110
2. 76.640
3. 78.600
4. 80.410

Virtual disk,single file,growable (單一虛擬硬碟,隨需求而變大)
1. 79.000
2. 80.100 (開始前,做了一下 fstrim,這一輪沒有較快,是下一輪較快? )
3. 77.120
4. 77.850

看來,效能差不多,有時會較慢,可能是同時做其他事,受到影響。使用 ghost 11 把 guest OS 的全部磁區都改成個別虛擬磁碟,然後再重測一下執行時間,結果如下。
1. 79.530
2. 77.140
3. 76.770 (開始前,fstrim 一次)
4. 78.450

換成虛擬磁碟後,好處之一是,執行 fstrim,不用關機後再執行。

2017年10月12日 星期四

Intel 600p M.2 512GB SSD 安裝

Intel 600P系列 512GB M.2 2280 PCI-E 固態硬碟,和 Intel 545s系列 512GB 2.5吋 SATAⅢ固態硬碟,價格差不多,甚至前者還便宜一些些,在6千元左右 (2017年10月)。可是 M2 512GB SSD 的讀取速度卻是 SATA 介面的 3倍,不過 較小容量的 M2 SSD 就沒有這麼快了。剛好目前的主機板可以使用 M2 的 SSD,就試試看這個 600P 的 SSD。聽說這個 M2 的 SSD 很容易過熱,飆到70度的溫度,自動降速,就順便買個專用的散熱片來用。

Intel 600P系列 512GB M.2 2280 PCI-E 固態硬碟規格
- 讀取速度 1775 MB/s
- 寫入速度 560 MB/s
- 隨機讀取 128,500 IOPS
隨機寫入 128,000 IOPS
- 3D NAND (TLC)

我用的主機板是 ASUS STRIX X99 GAMING,開機時,BIOS 的開機選單,顯示 Intel - SSDPEKKW512G7。

因為這個是 PCI 裝置,所以不會出現在 SATA 的裝置上,也不會顯示 /dev/sdx 的裝置。

要使用 lspci 來檢視該裝置的訊息。 # lspci -vvvv -s 3:0
03:00.0 Non-Volatile memory controller: Intel Corporation Device f1a5 (rev 03) (prog-if 02 [NVM Express])
Subsystem: Intel Corporation Device 390a
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 32 bytes
Interrupt: pin A routed to IRQ 11
NUMA node: 0
Region 0: Memory at fb500000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [70] Express (v2) Endpoint, MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s unlimited, L1 unlimited
ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset+ SlotPowerLimit 0.000W
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop- FLReset-
MaxPayload 128 bytes, MaxReadReq 512 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #0, Speed 8GT/s, Width x4, ASPM L1, Exit Latency L0s <1us, L1 <8us
ClockPM+ Surprise- LLActRep- BwNot- ASPMOptComp+
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- CommClk+
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 8GT/s, Width x4, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
DevCap2: Completion Timeout: Range ABCD, TimeoutDis+, LTR+, OBFF Via message
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR-, OBFF Disabled
LnkCtl2: Target Link Speed: 8GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete+, EqualizationPhase1+
EqualizationPhase2+, EqualizationPhase3+, LinkEqualizationRequest-
Capabilities: [b0] MSI-X: Enable- Count=16 Masked-
Vector table: BAR=0 offset=00002000
PBA: BAR=0 offset=00002100
Capabilities: [100 v2] Advanced Error Reporting
UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr-
CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
Capabilities: [158 v1] #19
Capabilities: [178 v1] Latency Tolerance Reporting
Max snoop latency: 0ns
Max no snoop latency: 0ns
Capabilities: [180 v1] L1 PM Substates
L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
  PortCommonModeRestoreTime=10us PortTPowerOnTime=10us


設定 kernel 驅動程式 NVM Express block device

CONFIG_BLK_DEV_NVME:

The NVM Express driver is for solid state drives directly
connected to the PCI or PCI Express bus.  If you know you
don't have one of these, it is safe to answer N.

To compile this driver as a module, choose M here: the
module will be called nvme.

重新編讀 kernel
# make -j4 && make modules_install
# mount /dev/sda2 /boot
# make install

在載入 驅動程式後,用 lsblk指令,就會看到列出的裝置,開頭是 nvmexxx。
# lsblk
NAME                       MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop1                        7:1    0     2G  0 loop 
└─docker-8:5-22809896-pool 253:0    0   100G  0 dm   
loop0                        7:0    0   100G  0 loop 
└─docker-8:5-22809896-pool 253:0    0   100G  0 dm   
sda                          8:0    0 894.3G  0 disk 
├─sda4                       8:4    0   100G  0 part /
├─sda2                       8:2    0   150M  0 part 
├─sda5                       8:5    0   500G  0 part /home
├─sda3                       8:3    0    10G  0 part [SWAP]
└─sda1                       8:1    0     2M  0 part 
nvme0n1                    259:0    0   477G  0 disk 

以上,出現 nvme 的 disk。

接著,就可以開始分割和使用硬碟了。
# cfdisk /dev/nvme0n1

查看溫度,先安裝 nvme-cli
# emerge -av nvme-cli
# nvme smart-log /dev/nvme0
Smart Log for NVME device:nvme0 namespace-id:ffffffff
critical_warning                    : 0
temperature                         : 39 C
available_spare                     : 100%
available_spare_threshold           : 10%
percentage_used                     : 0%
data_units_read                     : 143,891
data_units_written                  : 560,305
host_read_commands                  : 3,315,582
host_write_commands                 : 15,738,256
controller_busy_time                : 52
power_cycles                        : 72
power_on_hours                      : 439
unsafe_shutdowns                    : 37
media_errors                        : 0
num_err_log_entries                 : 0
Warning Temperature Time            : 0
Critical Composite Temperature Time : 0
Thermal Management T1 Trans Count   : 0
Thermal Management T2 Trans Count   : 0
Thermal Management T1 Total Time    : 0
Thermal Management T2 Total Time    : 0


2017年10月8日 星期日

在 Windows Server 2003 安裝 PHP 5.6.24

在微軟的支持下,PHP 可以在 Windows 的平台上,順利且有效率的運作。其中,包括 fastcgi、sqlsrv、及 wincache 等,是由微軟所支持提供的。

但我個人猜測,也是在微軟的干預下,以 Windows Server 2003 及 Windows XP 推出已超過 10 年為理由,決定從 PHP 5.5 開始,不再支持這兩個 OS。因此在這兩個廣泛使用的 OS 上,就無法安裝執行新版的 PHP,只能繼續堅守 PHP 5.4 以前的版本了。

Windows Server 2003,和 2008 以後的 OS 比起來,只需要較小的硬碟空間,在 VM 上安裝執行,非常據有優勢。因此,直到目前 (2017年) 我們還是繼續堅守著 2003。

每過一段時間,我就會在網路上搜尋,是否有在 Windows Server 2003 安裝 PHP 5.6 的可能性。直到最近,才在 Stack Overflow 上找到一段問答,How to install PHP 5.5 on WinXp 。在這討論裡,也是常見的,已經停止支援等等的話,但有一小段不小心就會遺漏的留言
But there is an unofficial build of PHP 5.6 at http://www.apachelounge.com/viewtopic.php?t=6334
這真是讓人興奮的話。到這時才知道,已有人重新修補編譯 PHP 5.6.4,讓它可以在 2003/XP 上執行,雖然,特別提醒的那一句話 "Play with it, do not use in in production ... " 讓人很不安心,但終究是有了可能性。

後來,在 github 上,也找到有人說明修補和編譯的作法,ProgerXP/php-5.6-xp。也照著做了,不過,後來搞清楚那是針對 Apache 的作法,也就是編出來是 thread-safe 的執行檔。但是,在 cgi 模式下,要用 non-thread-safe 的作法,才能有較好的效率,因此,也就放棄了。

很幸運的,後來找到一個中文的網頁,PHP 7 and PHP 5.6 for Windows XP/2003。它只是建立了一個 nonxp.dll,再修改 exe 和 dll 的相關資訊,讓它可以在 2003/XP 上執行。

雖然,它也改了 PHP 7.0,讓它可以在 2003/XP 上執行,但是可以使用的 sqlsrv driver 只有到 PHP 5.6,請參考 Unofficial Microsoft SQL Server Driver for PHP (sqlsrv),所以,我只有使用 PHP 5.6 這個版本。安裝後,稍微比較了一下效能,PHP 5.6 的效能大約是 PHP 5.4 的兩倍,的確很吸引人。

目前,我在其中一部 Windows 2003 的伺服器上,使用修改過的 PHP 5.6.24,等一段時間後,確認沒有問題,再全面改用。有空,也要看一下 nonxp 的原始碼,針對用到其中的function 的功能,加以測試,以確認一切是正常的,用起來才會安心。

GitHub 上的原始碼

在取得 nonxp.dll 的原作者的同意後,已將 nonxp.dll 及 補丁工具的程式上傳 github: php-5.6-xp-2003

碰到的錯誤

採用 nonxp.dll 的作法,版本 PHP-5.6.24,使用 fastcgi 模式,送出 header('Content-Type: application/javascript'); 時,會產生 IIS 500 的錯誤。但是,讓人懊惱的是,有時會連續出錯,有時又很正常。對了,只要動到 Laravel 5.0 的 routes.php,就會一直出錯,這個檔到底用到了什麼功能,以致於如此? 再試用 Apache Lounge 的討論區的 Jan-E 所改的 PHP-5.6.4,一樣也會有此問題。再切回 PHP 5.4 就完全沒問題。

後來猜測可能是 Laravel 5.0 中的某些部分,在 PHP-5.6.24 下,會出錯。例如 nette/tracy
在 PHP 5.4 和 Laravel 5.0 下,可以安裝,但不能正常運作。

再次測試,把應用程式,搬到 Laravel 5.1 下,看起來,能正常運作,不會一直出現 IIS 500 的錯誤,再持續觀察吧。

2017年10月1日 星期日

Slim 2 筆記

Middleware、Hook 的呼叫順序

Middleware, before next->call()
Hook slim.before
Hook slim.before.router
Hook slim.before.dispatch
-------------------------------------
response body render
echo 的內容會寫入 output buffer
-------------------------------------
Hook Middleware, after next->call()
Hook slim.after.dispatch
Hook slim.after.router
Hook slim.after

2017年9月29日 星期五

PHP 7 and PHP 5.6 for Windows XP/2003

Original page: http://www.lindasc.com/php/  (Here is just a translation.)
PHP Version: 7.0.9 / 5.6.24
Updated: 2016-7-28
Supported OS: Windows XP/2003
Description:
  Instead of patching and rebuilding the whole PHP completely, which is a complicated work, this work implements the API functions that are only available after Vista and then patches the import descriptors of the executable files.
  The implemented functions are listed as follows.

DLL file function name ver. of nonxp.dll
iphlpapi.dll if_nametoindex 0.0.1.11
kernel32.dll GetFinalPathNameByHandleA 0.0.2.20
GetFinalPathNameByHandleW 0.0.2.20
GetTickCount64 0.0.1.11
InitializeConditionVariable 0.0.4.40
InitializeCriticalSectionEx 0.0.3.30
SleepConditionVariableCS 0.0.4.40
WakeAllConditionVariable 0.0.4.40
WakeConditionVariable 0.0.4.40
shell32.dll SHGetKnownFolderPath 0.0.3.30
ws2_32.dll WSASendMsg 0.0.1.11
inet_ntop 0.0.1.11
inet_pton 0.0.1.11

  Instructions of installation:
  PHP 7: the OS must install IE8 and VC14 redistributable package.
      PHP 5.6: the OS must install IE8 and VC11 redistributable package.
  Download links:
Source code
Source code of nonxp.dll
The source code of nonxp.dll and the patch tool have been uploaded to github, php-5.6-xp-2003, according to the permission of the original author.

2017年9月20日 星期三

Slim 2 與 Laravel 5.0,小比一下

使用 Laravel 一陣子了,好像只用到其中一小部分,如 Query builder、Request、View 等。然後,可以使用 Composer 將一些東西包進 Slim,程式就可以跑了。

環境是 Windwos server 2003+fast-cgi,PHP 為 PHP 5.4.45+wincache 及 PHP 5.6.24+opcache。

 $ ab -n 100 -c 4 http://10.161.81.188/test/sdic_qry/index.php/sql_qry?dep=P020

hello-world,只是單純送出 "Hello, world!" 的字串,用來測試空的 framework 的性能。Slim 2 有加裝一些 package,也設定一些習慣使用的 Laravel 的靜態介面。

sql_qry 則進行資料庫的 query,用以測試資料庫存取的影響。其中,後端資料庫為安裝在 VM 的 SQL 2000 server。

PHP 5.6.24

Slim 2,debug off,hello-world,,Requests per second:    189.16 [#/sec]
Slim 2,debug on,hello-world,Requests per second:    187.35 [#/sec] (mean)
Slim 2,debug off,sql_qry,Requests per second:    143.17 [#/sec] (mean)
Slim 2,debug on,sql_qry,Requests per second:    129.30 [#/sec] (mean)

Slim 3,debug on,hello-world,Requests per second:    143.44 [#/sec] (mean)
Slim 3,debug off,sql_qry,Requests per second:    118.56 [#/sec] (mean)

Laravel 5.0,hello-world, 66.33 [#/sec] (mean)
Laravel 5.0,sql_qry,5.6.24,Requests per second:    55.74 [#/sec] (mean)

Slim 2,debug off,laravel-session (file/database),Requests per second:    60 [#/sec] (mean)

PHP 5.4.45

Slim 2,debug on,hello-world,Requests per second:    80.37 [#/sec] (mean)
Slim 2,debug off,hello-world,Requests per second:    110.83 [#/sec] (mean)
Slim 2,debug off,sql_qry,Requests per second:    87.60 [#/sec] (mean)
Slim 2,debug on,sql_qry,Requests per second:    72.85 [#/sec] (mean)
L5,sql_qry,5.6.24,Requests per second:    25.22 [#/sec] (mean)
L5,hello-world, 29.75 [#/sec] (mean)

測試中,Tracy/Debuger 會造成 Failed requests。
在 Slim 2 中,加上 Laravel 的 session 後,效能降到和 Laravel 差不多。
其中,session 的垃圾收集,會大幅的拖慢效能。垃圾收集的時機,由設定中的 'lottery' => [2, 100] 來決定,此代表 50 次,會做一次垃圾收集。減少垃圾收集的機率,可提升效能。
請參考 PHP Session Garbage Collection: The unknown performance bottleneck
所以,是否使用 Laravel 的 session,會是一個決擇。然而,其可以選擇不同的 drvier,實在是非常方便的作法。

以下為使用下列指令測試的結果

$ ab -n 100 -c 10 http://10.161.81.188/test/sdic_qry/index.php/cou_cur/introduction?cur=P020

Slim 2 的結果如下

Server Software:        Microsoft-IIS/6.0
Server Hostname:        10.161.81.188
Server Port:            80

Document Path:          /test/sdic_qry/index.php/cou_cur/introduction?cur=P020
Document Length:        18064 bytes

Concurrency Level:      10
Time taken for tests:   1.373 seconds
Complete requests:      100
Failed requests:        26
   (Connect: 0, Receive: 0, Length: 26, Exceptions: 0)
Write errors:           0
Total transferred:      1829852 bytes
HTML transferred:       1806452 bytes
Requests per second:    72.85 [#/sec] (mean)
Time per request:       137.275 [ms] (mean)
Time per request:       13.727 [ms] (mean, across all concurrent requests)
Transfer rate:          1301.74 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.7      0       4
Processing:    52  129  41.4    119     330
Waiting:       50  128  41.4    118     329
Total:         52  130  41.5    120     331

Percentage of the requests served within a certain time (ms)
  50%    120
  66%    131
  75%    140
  80%    145
  90%    178
  95%    206
  98%    308
  99%    331
 100%    331 (longest request)

Laravel 5.0 的結果如下

Server Software:        Microsoft-IIS/6.0
Server Hostname:        10.161.81.188
Server Port:            80

Document Path:          /test/sdic_for_reg/index.php/cou_cur?cur=P020
Document Length:        14987 bytes

Concurrency Level:      10
Time taken for tests:   3.927 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      1606344 bytes
HTML transferred:       1498700 bytes
Requests per second:    25.46 [#/sec] (mean)
Time per request:       392.702 [ms] (mean)
Time per request:       39.270 [ms] (mean, across all concurrent requests)
Transfer rate:          399.46 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   1.1      0       5
Processing:   146  372  95.2    346     738
Waiting:      143  370  95.0    345     737
Total:        147  373  95.4    347     739

Percentage of the requests served within a certain time (ms)
  50%    347
  66%    400
  75%    436
  80%    463
  90%    495
  95%    527
  98%    626
  99%    739
 100%    739 (longest request)

結果是 Slim 2 大概是 Laravel 5.0 的 3 倍。然後,隨著程式成長,使用 Slim 的環境,也由每秒完成的 request 也由 72 個降到 65 個左右。

再 Optimizing Composer's autoloader 一下,指令 composer  dumpautoload -o,又稍微提升到每秒完成 75 個 request。

2018-01-29 測試

應用程式的條件,使用 Laravel 的 DB 和 View,關掉 debug。在 optimize 以前,大約 100 [#/sec],optimize 後,約 118 [#/sec]。
不過,結果不是很穩定,後來再測,降到約 70 [#/sec]。

使用 ApacheBench (ab) 測 Slim 變得很慢

參考 HTTP, Slim and ApacheBench

使用 Apache 伺服器跑 Slim 時,用 ab 測效能,會變得很慢,一秒才處理一個 request。
這是因為 ab 送出 HTTP/1.0 的 request,它會等伺服器關閉 connection。可是 Slim 卻回應 HTTP/1.1 的 header,因此雙方在互相等待連線關閉。

解決辦法,針對所有的 HTTP/1.0 或沒有 Connection header 的 request,都送出 "Connection: close" 。在 Slim 初始化後,加上下面的程式碼。

if ($_SERVER['SERVER_PROTOCOL'] == 'HTTP/1.0' && 
   empty($_SERVER['HTTP_CONNECTION'])
) {
    // header('Connection: close');
    $app->response->headers->set('Connection', 'close');
}


2017年9月18日 星期一

透過 WINE 安裝 FileZilla ftp server (失敗)

因為想把一些在 Windows 2003 server 上跑的服務,移到 docker 的虛擬平台上,所以想透過 WINE 安裝 FileZilla ftp server。先說測試結果 -- 失敗,雖然離成功只剩一小步,但可能無法跨越。

起先在 docker 下執行 WINE,參考 suchja/wine 的作法。
在 docker host 上,不需安裝 X window,使用 suchja/x11server 來當圖形界面輸出。
docker run -d --name display -e VNC_PASSWORD=newPW -p 5900:5900 suchja/x11server

然後啟動  Wine container,如下:
docker run --rm -it --link display:xserver --volumes-from display suchja/wine:latest /bin/bash

啟動 container 後,啟始 wine
wine wineboot --init

下載安裝檔
curl http://xxx.com/yyy/FileZilla_Server-0_9_43.exe -o FileZilla_Server-0_9_43.exe
XP 支援的版本,只到 0.9.43。

安裝,在便令視窗下指令,然後,要透過 vnc client 連上 server,操作圖形視窗。
wine FileZilla_Server-0_9_43.exe

注意,安裝時,需要 root 的身分,才能開啟 port,ftp server才能啟動。在上述指令,不要加上 --rm 的選項,離開 container 的互動介面後,將此 container 存成 image。
docker commit f26355b23ac6 wine-filezilla-server

使用新的 image 啟動 container,使用下列指令啟動 ftp server,以及進入管理界面。
wine FileZilla\ Server.exe /compat /start &
wine FileZilla\ Server\ Interface.exe &

管理界面,有點怪怪的,右側 acount list 不會出現,按一下左邊的 item,就會出現。可以建立帳號,但指定目錄,有點不太行。

建好帳號後,用 client 端登入,可以登入,但是讀資料失敗,ls -aL 無法成功。
"503 Bad sequence of commands" 的錯誤,推測 wine 不適合執行網路伺服器的程式。

以上,記錄安裝測試的大致過程,供做參考。

2017年9月12日 星期二

ThinkPad Trackpoint 設定



$xinput
⎡ Virtual core pointer                     id=2 [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer               id=4 [slave  pointer  (2)]
⎜   ↳ Logitech USB Receiver                   id=12 [slave  pointer  (2)]
⎜   ↳ Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint id=8 [slave  pointer  (2)]
⎣ Virtual core keyboard                   id=3 [master keyboard (2)]
    ↳ Virtual core XTEST keyboard             id=5 [slave  keyboard (3)]
    ↳ Power Button                             id=6 [slave  keyboard (3)]
    ↳ Power Button                             id=7 [slave  keyboard (3)]
    ↳ Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint id=9 [slave  keyboard (3)]
    ↳ Logitech USB Receiver                   id=13 [slave  keyboard (3)]

$xinput list-props "pointer:Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint"
Device 'Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint':
Device Enabled (152): 1
Coordinate Transformation Matrix (154): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
Device Accel Profile (413): 0
Device Accel Constant Deceleration (414): 1.000000
Device Accel Adaptive Deceleration (415): 1.000000
Device Accel Velocity Scaling (416): 10.000000
Device Product ID (271): 6127, 24585
Device Node (272): "/dev/input/event14"
Evdev Axis Inversion (417): 0, 0
Evdev Axes Swap (419): 0
Axis Labels (420): "Rel X" (162), "Rel Y" (163)
Button Labels (421): "Button Left" (155), "Button Middle" (156), "Button Right" (157), "Button Wheel Up" (158), "Button Wheel Down" (159), "Button Horiz Wheel Left" (160), "Button Horiz Wheel Right" (161), "Button Unknown" (412), "Button Unknown" (412), "Button Unknown" (412), "Button Unknown" (412), "Button Unknown" (412), "Button Unknown" (412), "Button Unknown" (412), "Button Unknown" (412), "Button Unknown" (412), "Button Unknown" (412), "Button Unknown" (412), "Button Unknown" (412)
Evdev Scrolling Distance (422): 0, 0, 0
Evdev Middle Button Emulation (423): 0
Evdev Middle Button Timeout (424): 50
Evdev Middle Button Button (425): 2
Evdev Third Button Emulation (426): 0
Evdev Third Button Emulation Timeout (427): 1000
Evdev Third Button Emulation Button (428): 3
Evdev Third Button Emulation Threshold (429): 20
Evdev Wheel Emulation (430): 0
Evdev Wheel Emulation Axes (431): 0, 0, 4, 5
Evdev Wheel Emulation Inertia (432): 10
Evdev Wheel Emulation Timeout (433): 200
Evdev Wheel Emulation Button (434): 4
Evdev Drag Lock Buttons (435): 0

$xinput set-prop "pointer:Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint" "Evdev Wheel Emulation" 1
$ xinput set-prop "pointer:Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint" "Evdev Wheel Emulation Button" 2
$ xinput set-prop "pointer:Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint" "Evdev Wheel Emulation Timeout" 200


The need for the "--with-bdeps y" and "--backtrack 100" switches will go away over upcoming



2017年9月9日 星期六

使用 docker 安裝及執行 Laravel

因為環境的關係,例如,在 Windows server 2003 下,只能跑 PHP 5.4,就限制了只能使用Laravel 5.0。而要裝 Laravel 5.0,也必需使用 PHP 5.4 ~ 5.6 的版本來安裝。相對的,使用 CentOS,則能使用最新版本的 PHP,相對的,也必須使用較高版本的 Laravel。

可是,自己個人使用的電腦,一定不想要同時安裝各種版本的 PHP,通常也不允許。甚至,像 PHP 5.4,因為官方不再支援,有可能無法安裝。在這種情形下,docker 實在是一個很理想的環境或工具。在這裡,要安裝 Laravel 5.0,選擇使用的 image 是 composer/composer:php5-alpine,它用的是 PHP 5.6,雖然標註為 DEPRECATED,但還是能用的。

我是習慣在一個專用的目錄下,放置和 Laravel 相關的專案,因此,將 composer 的 cache 也放在此目錄下,就可以省下很多等待下載的時間。其中 "-v $(pwd)/cache:/composer" 的選項,就是指定存放 cache 的 volume。

在建立專案時,會在該目錄下建立一個新的目錄,因此用 "-v $(pwd):/app" 來指定 volume。但是 update 時,則需在該專案的目錄下,因此 volume 的指定便成為 "-v $(pwd)/la-50:/app",而不用真的切換目錄。

$ docker run --rm -v $(pwd):/app  -v /cache:/composer composer/composer:php5-alpine create-project laravel/laravel la-50 "5.0.*" --prefer-dist

# 移險 la-50/vendor/compiled.php 後,進行 update
$ cd la-50
$ rm vendor/compiled.php

$ docker run --rm -v $(pwd):/app  -v ~/php-projects/cache:/composer composer/composer:php5-alpine update

接著用 PHP 5.4 來執行測試。注意,這裡使用的 image 已安裝所需的 PHP extension 了。
docker run -it --rm -v $(pwd):/app -p 8000:8000 php54_app php /app/artisan --host=0.0.0.0 serv

然後,使用瀏覽器開啟 http://localhost:8000/ 即可看到結果。













2017年6月28日 星期三

設定 VirtualBox VM 的 service


註冊 VM,然後列出現有的 VM。
ajax $VBoxManage registervm ~/VirtualBox\ VMs/Win7-work/Win7-work.vbox
 ajax $ VBoxManage list vms
"Win7-work" {5ca8a108-379f-410a-a1e5-ac6d46ad2ac9} 

移除 VM 的註冊。
ajax $VBoxManage unregistervm "Win7-work"

建立 /usr/lib/systemd/system/vboxvmservice@.service
[Unit]
Description=VBox Virtual Machine %i Service

[Service]
User=ajax
Group=vboxusers
ExecStart=/opt/bin/VBoxHeadless -s %i
ExecStop=/opt/bin/VBoxManage controlvm %i savestate

[Install]
WantedBy=multi-user.target


啟動 VM 的服務
ajax $sudo systemctl start vboxvmservice@Win7-work.service

列出啟動的 VM 的服務
ajax $systemctl list-units | grep vbox
vboxvmservice@Win7-work.service          loaded active running   VBox Virtual Machine Win7-work Service                                                           
system-vboxvmservice.slice                      loaded active active    system-vboxvmservice.slice 

rebuild 會幾乎把所有的 package 都重新裝一次,

2017年6月18日 星期日

megaraid 操作 -- 於 Acer Altos R360 f3 伺服器

此篇本是為 Acer 的伺服器而整理,到後來變成 megaraid 的操作整理,就把標題給改了。
-- 2020-03-07 記

新購一部 Acer Altos R360 f3 伺服器 (2016 年),整理一下相關資料,以供日後參考。
機器原本是裝 vSphere ESXi,最近想玩 Docker,就重灌 Gentoo Linux。選擇 Gentoo,因為它是滾動發行,沒有升級的問題。另外,因為要自己編 kernel,必須先收集相關的硬體資訊,不然,就無法正常開機了。

Acer Altos R360 f3 的配備

CPU Intel(R) Xeon(R) CPU E5-2620 v4 @ 2.10GHz (family: 0x6, model: 0x4f, stepping: 0x1)
8 x 2.5" disks
Intel Integrated RAID Module RMS3CC080
Intel I350 Gigabit Network Connection

嗯,相對於買 HP 或 ASUS 的伺服器,買宏碁的伺服器的好處是,8個磁碟的 tray 都附上,可以買自己想買的磁碟,不用多花錢。

可惜透過中信局買的 Acer 伺服器,只能用 2.5" 的硬碟。而 後來買的 ASUS 伺服器則採比較聰明的作法,在 3.5" 的硬碟匣 (tray) 上的打洞,可同時裝 2.5" 的硬碟,所以後來都買 ASUS 伺服器,雖然要再另外買硬碟匣,但還是比較划算。

lspci 顯示的硬體資料

01:00.0 RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS-3 3108 [Invader] (rev 02)
03:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)
07:00.0 VGA compatible controller: Matrox Electronics Systems Ltd. MGA G200e [Pilot] ServerEngines (SEP1) (rev 05)

dmesg 摘要

megaraid cmm: 2.20.2.7 (Release Date: Sun Jul 16 00:01:03 EST 2006)
megaraid: 2.20.5.1 (Release Date: Thu Nov 16 15:32:35 EST 2006)
megasas: 06.811.02.00-rc1
megaraid_sas 0000:01:00.0: FW now in Ready state
scsi host10: Avago SAS based MegaRAID driver
scsi 10:2:0:0: Direct-Access     Intel    RMS3CC080        4.66 PQ: 0 ANSI: 5
random: fast init done
sd 10:2:0:0: [sda] 1167966208 512-byte logical blocks: (598 GB/557 GiB)

igb: Intel(R) Gigabit Ethernet Network Driver - version 5.4.0-k
igb 0000:03:00.0: added PHC on eth0

将 megaraid 卡磁盘 raid0 改为 JBOD 模式

相關說明,參考: 将 megaraid 卡磁盘 raid0 改为 JBOD 模式
megaraid 卡使用 JBOD 模式,磁盘可以直接被系统识别,使用 smartctl 查看 SMART 信息和 直连 SAS 卡一样。
# megacli -PDList -aALL -Nolog|grep '^Firm'
Firmware state: JBOD
Firmware state: Online, Spun Up
Firmware state: Online, Spun Up
Firmware state: Online, Spun Up
Firmware state: Online, Spun Up

行有時候要確定那個硬碟壞了,用 grep 的 OR 條件來找,比較快。

# megacli -PDList -aALL -Nolog | grep '^Firm\|Slot'
Slot Number: 0
Firmware state: JBOD
Slot Number: 3
Firmware state: Online, Spun Up
Slot Number: 4
Firmware state: Online, Spun Up
Slot Number: 6
Firmware state: Failed
Slot Number: 7
Firmware state: Online, Spun Up
Slot Number: 8
Firmware state: Online, Spun Up
Slot Number: 9
Firmware state: Online, Spun Up
Slot Number: 10
Firmware state: Online, Spun Up
Slot Number: 11
Firmware state: Online, Spun Up

硬碟使用紀錄

為了省錢,使用4顆 HGST 的 SATA 1TB 硬碟,建立 RAID 6 。2017年 6月,11月中,壞掉一顆,繼續觀察中。
後來,試著把它重插回去,看起來又是正常的。下指令,結果如下

# megacli -PDList -aALL -Nolog|grep '^Firm'
Firmware state: JBOD
Firmware state: Online, Spun Up
Firmware state: Rebuild
Firmware state: Online, Spun Up
Firmware state: Online, Spun Up

查看硬碟的編號如下
# megacli -PDList -aALL -Nolog|grep -iE 'enclosure device id|slot Number'
Enclosure Device ID: 0
Slot Number: 0
Enclosure Device ID: 0
Slot Number: 3
Enclosure Device ID: 0
Slot Number: 4
Enclosure Device ID: 0
Slot Number: 6

RAID 6 壞掉一顆硬碟,查詢的狀態
# megacli -ldinfo -lALL -aALL
                                     
Adapter 0 -- Virtual Drive Information:
Virtual Drive: 1 (Target Id: 1)
Name                :VD_24TB
RAID Level          : Primary-6, Secondary-0, RAID Level Qualifier-3
Size                : 21.830 TB
Sector Size         : 512
Is VD emulated      : Yes
Parity Size         : 10.915 TB
State               : Partially Degraded
Strip Size          : 256 KB
Number Of Drives    : 6
Span Depth          : 1
Default Cache Policy: WriteBack, ReadAhead, Direct, No Write Cache if Bad BBU
Current Cache Policy: WriteThrough, ReadAhead, Direct, No Write Cache if Bad BBU
Default Access Policy: Read/Write
Current Access Policy: Read/Write
Disk Cache Policy   : Disk's Default
Encryption Type     : None
Bad Blocks Exist: No
PI type: No PI

Is VD Cached: No

Exit Code: 0x00

下指令察看 rebuild 進度
# watch -n 30 'megacli -PDRbld -ShowProg -PhysDrv [0:4] -aALL'

Every 30.0s: megacli -PDRbld -ShowProg -PhysDrv [0:...  Mon Mar  2 10:08:42 2020

Rebuild Progress on Device at Enclosure 0, Slot 4 Completed 6% in 1 Minutes.

Exit Code: 0x00

讓 LED 閃爍 (LED blink)

Syntax: megacli -PdLocate <-start|-stop> -physdrv[<enclosure#>:<disk#>] -a<adapter#>

In this example we will locate disk 0 on adapter 0:
[root@localhost MegaCli]# megacli -PdLocate -start -physdrv[252:0] -a0
 Adapter: 0: Device at EnclId-252 SlotId-0 — PD Locate Start Command was successfully sent to Firmware
 Exit Code: 0x00
 [root@localhost MegaCli]# 
相關資料及指令,參考 LSI MegaRAID SAS
在 github 上,有原作者寫的 megaclisas-status,可供週期性檢查 disk array 的狀態。

關掉/開啟 BEEP 聲

在 rebuild 時,關掉聲音
# megacli -AdpSetProp AlarmSilence -a0
  Adapter 0: Set alarm to Silenced success.
  Exit Code: 0x00

Enable 警告聲音
# megacli -AdpGetProp AlarmDsply -a0
  Adapter 0: Alarm Status is Enabled
  Exit Code: 0x00

查詢警告聲音的設定
# megacli -AdpGetProp AlarmDsply -a0
  Adapter 0: Alarm Status is Enabled
  Exit Code: 0x00

警告聲的代碼: Controller beep codes

Consistency Check 

不時就會看到硬碟的燈一直在閃,原來它會定時在背後執行 Consistency Check。查看 Consistency Check 目前正在進行的工作
# megacli -LDCC -ShowProg -lall -aall 

To see next scheduled Consistency Check time,預設一個星期執行一次。
# megacli -AdpCcSched -Info -aALL
                                     
Adapter #0

Operation Mode: Concurrent
Execution Delay: 168
Next start time: 03/07/2020, 03:00:00
Current State: Active
Number of iterations: 21
Number of VD completed: 1
Excluded VDs          : None
Exit Code: 0x00
Consistency Check 有兩種 mode, concurrent mode 及 sequencial mode,可以自己更改。Note: After change mode from disable to concurrent/sequencial, the next scheduled CC time will become year 2135, you have to set next scheduled run time again.

也可以更改 Consistency Check delay interval, Consistency Check Rate,亦可 manually start Consistency Check。

取得 Consistency Check Rate
# megacli -AdpGetProp CCRate -aALL
Adapter 0: Check Consistency Rate = 30% ##default 
If you get an error like "Consistency Check suspended on VD. . .", you can resume like so:
# MegaCli64 -LDCC -resume -lall -aall
At the end, if you want check Adapter properties, here is it
# MegaCli64 -AdpAllInfo -aALL

網誌存檔