篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了转帖通过PHP读取dbf数据(visual fox pro,VFP数据库),官方的dbase无法读取字段为类型memo的数据,国外网站的解决方案 How to read FoxPro Memo w(代相关的知识,希望对你有一定的参考价值。
原帖为英文,地址: http://stackoverflow.com/questions/1947348/how-to-read-foxpro-memo-with-php
Alright, I have carefully studied the MSDN specifications of DBF and FPT file structures and the outcome is a beautiful PHP class which can open a DBF and (optional) an FPT memo file at the same time. This class will give you record after record and thereby fetch any memos from the memo file - if opened.
1 class Prodigy_DBF {
2 private $Filename, $DB_Type, $DB_Update, $DB_Records, $DB_FirstData, $DB_RecordLength, $DB_Flags, $DB_CodePageMark, $DB_Fields, $FileHandle, $FileOpened;
3 private $Memo_Handle, $Memo_Opened, $Memo_BlockSize;
4
5 private function Initialize() {
6
7 if($this->FileOpened) {
8 fclose($this->FileHandle);
9 }
10
11 if($this->Memo_Opened) {
12 fclose($this->Memo_Handle);
13 }
14
15 $this->FileOpened = false;
16 $this->FileHandle = NULL;
17 $this->Filename = NULL;
18 $this->DB_Type = NULL;
19 $this->DB_Update = NULL;
20 $this->DB_Records = NULL;
21 $this->DB_FirstData = NULL;
22 $this->DB_RecordLength = NULL;
23 $this->DB_CodePageMark = NULL;
24 $this->DB_Flags = NULL;
25 $this->DB_Fields = array();
26
27 $this->Memo_Handle = NULL;
28 $this->Memo_Opened = false;
29 $this->Memo_BlockSize = NULL;
30 }
31
32 public function __construct($Filename, $MemoFilename = NULL) {
33 $this->Prodigy_DBF($Filename, $MemoFilename);
34 }
35
36 public function Prodigy_DBF($Filename, $MemoFilename = NULL) {
37 $this->Initialize();
38 $this->OpenDatabase($Filename, $MemoFilename);
39 }
40
41 public function OpenDatabase($Filename, $MemoFilename = NULL) {
42 $Return = false;
43 $this->Initialize();
44
45 $this->FileHandle = fopen($Filename, "r");
46 if($this->FileHandle) {
47 // DB Open, reading headers
48 $this->DB_Type = dechex(ord(fread($this->FileHandle, 1)));
49 $LUPD = fread($this->FileHandle, 3);
50 $this->DB_Update = ord($LUPD[0])."/".ord($LUPD[1])."/".ord($LUPD[2]);
51 $Rec = unpack("V", fread($this->FileHandle, 4));
52 $this->DB_Records = $Rec[1];
53 $Pos = fread($this->FileHandle, 2);
54 $this->DB_FirstData = (ord($Pos[0]) + ord($Pos[1]) * 256);
55 $Len = fread($this->FileHandle, 2);
56 $this->DB_RecordLength = (ord($Len[0]) + ord($Len[1]) * 256);
57 fseek($this->FileHandle, 28); // Ignoring "reserved" bytes, jumping to table flags
58 $this->DB_Flags = dechex(ord(fread($this->FileHandle, 1)));
59 $this->DB_CodePageMark = ord(fread($this->FileHandle, 1));
60 fseek($this->FileHandle, 2, SEEK_CUR); // Ignoring next 2 "reserved" bytes
61
62 // Now reading field captions and attributes
63 while(!feof($this->FileHandle)) {
64
65 // Checking for end of header
66 if(ord(fread($this->FileHandle, 1)) == 13) {
67 break; // End of header!
68 } else {
69 // Go back
70 fseek($this->FileHandle, -1, SEEK_CUR);
71 }
72
73 $Field["Name"] = trim(fread($this->FileHandle, 11));
74 $Field["Type"] = fread($this->FileHandle, 1);
75 fseek($this->FileHandle, 4, SEEK_CUR); // Skipping attribute "displacement"
76 $Field["Size"] = ord(fread($this->FileHandle, 1));
77 fseek($this->FileHandle, 15, SEEK_CUR); // Skipping any remaining attributes
78 $this->DB_Fields[] = $Field;
79 }
80
81 // Setting file pointer to the first record
82 fseek($this->FileHandle, $this->DB_FirstData);
83
84 $this->FileOpened = true;
85
86 // Open memo file, if exists
87 if(!empty($MemoFilename) and file_exists($MemoFilename) and preg_match("%^(.+).fpt$%i", $MemoFilename)) {
88 $this->Memo_Handle = fopen($MemoFilename, "r");
89 if($this->Memo_Handle) {
90 $this->Memo_Opened = true;
91
92 // Getting block size
93 fseek($this->Memo_Handle, 6);
94 $Data = unpack("n", fread($this->Memo_Handle, 2));
95 $this->Memo_BlockSize = $Data[1];
96 }
97 }
98 }
99
100 return $Return;
101 }
102
103 public function GetNextRecord($FieldCaptions = false) {
104 $Return = NULL;
105 $Record = array();
106
107 if(!$this->FileOpened) {
108 $Return = false;
109 } elseif(feof($this->FileHandle)) {
110 $Return = NULL;
111 } else {
112 // File open and not EOF
113 fseek($this->FileHandle, 1, SEEK_CUR); // Ignoring DELETE flag
114 foreach($this->DB_Fields as $Field) {
115 $RawData = fread($this->FileHandle, $Field["Size"]);
116 // Checking for memo reference
117 if($Field["Type"] == "M" and $Field["Size"] == 4 and !empty($RawData)) {
118 // Binary Memo reference
119 $Memo_BO = unpack("V", $RawData);
120 if($this->Memo_Opened and $Memo_BO != 0) {
121 fseek($this->Memo_Handle, $Memo_BO[1] * $this->Memo_BlockSize);
122 $Type = unpack("N", fread($this->Memo_Handle, 4));
123 if($Type[1] == "1") {
124 $Len = unpack("N", fread($this->Memo_Handle, 4));
125 $Value = trim(fread($this->Memo_Handle, $Len[1]));
126 } else {
127 // Pictures will not be shown
128 $Value = "{BINARY_PICTURE}";
129 }
130 } else {
131 $Value = "{NO_MEMO_FILE_OPEN}";
132 }
133 } else {
134 $Value = trim($RawData);
135 }
136
137 if($FieldCaptions) {
138 $Record[$Field["Name"]] = $Value;
139 } else {
140 $Record[] = $Value;
141 }
142 }
143
144 $Return = $Record;
145 }
146
147 return $Return;
148 }
149
150 function __destruct() {
151 // Cleanly close any open files before destruction
152 $this->Initialize();
153 }
154 }
1 $Test = new Prodigy_DBF("customer.DBF", "customer.FPT");
2 while(($Record = $Test->GetNextRecord(true)) and !empty($Record)) {
3 print_r($Record);
4 }
It might not be an almighty perfect class, but it works for me. Feel free to use this code, but note that the class is VERY tolerant - it doesn‘t care if fread() and fseek() return true or anything else - so you might want to improve it a bit before using.
Also note that there are many private variables like number of records, recordsize etc. which are not used at the moment.
更多内容请查看原帖:http://stackoverflow.com/questions/1947348/how-to-read-foxpro-memo-with-php
以上是关于转帖通过PHP读取dbf数据(visual fox pro,VFP数据库),官方的dbase无法读取字段为类型memo的数据,国外网站的解决方案 How to read FoxPro Memo w(代的主要内容,如果未能解决你的问题,请参考以下文章