PHP ile FoxPro Memo nasıl okunur?

6 Cevap php

Visual FoxPro MySQL. DBF ve. FPT dosyalarını dönüştürmek zorunda. Şu anda benim script için. DBF dosyaları çalışır o açılır ve dbase_open () ve dbase_get_record_with_names onları okur () ve ardından MySQL INSERT komutları yürütür.

Ancak, bu. DBF dosyaları bazı alanlar tip MEMO ve bu nedenle. FPT biten bir ayrı dosyalarda saklanır. Nasıl bu dosyayı okuyabilirim?

I MSDN bu filetype teknik özelliklerini bulduk, ama ben (de, ben gerçekten bir simplier çözümü tercih ediyorum) I bayt-bilge PHP ile bu dosyayı okuyabilir bilmiyorum.

Herhangi bir fikir?

6 Cevap

Tamam, ben dikkatle DBF ve FPT dosya yapıları MSDN teknik özelliklerini inceledik ve sonuç aynı zamanda bir DBF ve (isteğe bağlı) FPT not dosyasını açabilirsiniz güzel bir PHP sınıfı. Bu sınıf kayıttan sonra size kayıt vermek ve böylece not dosyasından herhangi notları alıp - açarsa.

class Prodigy_DBF {
    private $Filename, $DB_Type, $DB_Update, $DB_Records, $DB_FirstData, $DB_RecordLength, $DB_Flags, $DB_CodePageMark, $DB_Fields, $FileHandle, $FileOpened;
    private $Memo_Handle, $Memo_Opened, $Memo_BlockSize;

    private function Initialize() {

        if($this->FileOpened) {
            fclose($this->FileHandle);
        }

        if($this->Memo_Opened) {
            fclose($this->Memo_Handle);
        }

        $this->FileOpened = false;
        $this->FileHandle = NULL;
        $this->Filename = NULL;
        $this->DB_Type = NULL;
        $this->DB_Update = NULL;
        $this->DB_Records = NULL;
        $this->DB_FirstData = NULL;
        $this->DB_RecordLength = NULL;
        $this->DB_CodePageMark = NULL;
        $this->DB_Flags = NULL;
        $this->DB_Fields = array();

        $this->Memo_Handle = NULL;
        $this->Memo_Opened = false;
        $this->Memo_BlockSize = NULL;
    }

    public function __construct($Filename, $MemoFilename = NULL) {
        $this->Prodigy_DBF($Filename, $MemoFilename);
    }

    public function Prodigy_DBF($Filename, $MemoFilename = NULL) {
        $this->Initialize();
        $this->OpenDatabase($Filename, $MemoFilename);
    }

    public function OpenDatabase($Filename, $MemoFilename = NULL) {
        $Return = false;
        $this->Initialize();

        $this->FileHandle = fopen($Filename, "r");
        if($this->FileHandle) {
            // DB Open, reading headers
            $this->DB_Type = dechex(ord(fread($this->FileHandle, 1)));
            $LUPD = fread($this->FileHandle, 3);
            $this->DB_Update = ord($LUPD[0])."/".ord($LUPD[1])."/".ord($LUPD[2]);
            $Rec = unpack("V", fread($this->FileHandle, 4));
            $this->DB_Records = $Rec[1];
            $Pos = fread($this->FileHandle, 2);
            $this->DB_FirstData = (ord($Pos[0]) + ord($Pos[1]) * 256);
            $Len = fread($this->FileHandle, 2);
            $this->DB_RecordLength = (ord($Len[0]) + ord($Len[1]) * 256);
            fseek($this->FileHandle, 28); // Ignoring "reserved" bytes, jumping to table flags
            $this->DB_Flags = dechex(ord(fread($this->FileHandle, 1)));
            $this->DB_CodePageMark = ord(fread($this->FileHandle, 1));
            fseek($this->FileHandle, 2, SEEK_CUR);    // Ignoring next 2 "reserved" bytes

            // Now reading field captions and attributes
            while(!feof($this->FileHandle)) {

                // Checking for end of header
                if(ord(fread($this->FileHandle, 1)) == 13) {
                    break;  // End of header!
                } else {
                    // Go back
                    fseek($this->FileHandle, -1, SEEK_CUR);
                }

                $Field["Name"] = trim(fread($this->FileHandle, 11));
                $Field["Type"] = fread($this->FileHandle, 1);
                fseek($this->FileHandle, 4, SEEK_CUR);  // Skipping attribute "displacement"
                $Field["Size"] = ord(fread($this->FileHandle, 1));
                fseek($this->FileHandle, 15, SEEK_CUR); // Skipping any remaining attributes
                $this->DB_Fields[] = $Field;
            }

            // Setting file pointer to the first record
            fseek($this->FileHandle, $this->DB_FirstData);

            $this->FileOpened = true;

            // Open memo file, if exists
            if(!empty($MemoFilename) and file_exists($MemoFilename) and preg_match("%^(.+).fpt$%i", $MemoFilename)) {
                $this->Memo_Handle = fopen($MemoFilename, "r");
                if($this->Memo_Handle) {
                    $this->Memo_Opened = true;

                    // Getting block size
                    fseek($this->Memo_Handle, 6);
                    $Data = unpack("n", fread($this->Memo_Handle, 2));
                    $this->Memo_BlockSize = $Data[1];
                }
            }
        }

        return $Return;
    }

    public function GetNextRecord($FieldCaptions = false) {
        $Return = NULL;
        $Record = array();

        if(!$this->FileOpened) {
            $Return = false;
        } elseif(feof($this->FileHandle)) {
            $Return = NULL;
        } else {
            // File open and not EOF
            fseek($this->FileHandle, 1, SEEK_CUR);  // Ignoring DELETE flag
            foreach($this->DB_Fields as $Field) {
                $RawData = fread($this->FileHandle, $Field["Size"]);
                // Checking for memo reference
                if($Field["Type"] == "M" and $Field["Size"] == 4 and !empty($RawData)) {
                    // Binary Memo reference
                    $Memo_BO = unpack("V", $RawData);
                    if($this->Memo_Opened and $Memo_BO != 0) {
                        fseek($this->Memo_Handle, $Memo_BO[1] * $this->Memo_BlockSize);
                        $Type = unpack("N", fread($this->Memo_Handle, 4));
                        if($Type[1] == "1") {
                            $Len = unpack("N", fread($this->Memo_Handle, 4));
                            $Value = trim(fread($this->Memo_Handle, $Len[1]));
                        } else {
                            // Pictures will not be shown
                            $Value = "{BINARY_PICTURE}";
                        }
                    } else {
                        $Value = "{NO_MEMO_FILE_OPEN}";
                    }
                } else {
                    $Value = trim($RawData);
                }

                if($FieldCaptions) {
                    $Record[$Field["Name"]] = $Value;
                } else {
                    $Record[] = $Value;
                }
            }

            $Return = $Record;
        }

        return $Return;
    }

    function __destruct() {
        // Cleanly close any open files before destruction
        $this->Initialize();
    }
}

Sınıfı bu gibi kullanılabilir:

    $Test = new Prodigy_DBF("customer.DBF", "customer.FPT");
    while(($Record = $Test->GetNextRecord(true)) and !empty($Record)) {
        print_r($Record);
    }

Bir şeye kadir mükemmel sınıf olmayabilir, ama bu benim için çalışıyor. Bu kodu kullanmak için çekinmeyin, ama sınıf çok hoşgörülü olduğuna dikkat - fread () ve fseek () doğru ya da başka bir şey dönerseniz umurumda değil - bu yüzden kullanmadan önce bunu biraz geliştirmek isteyebilirsiniz.

Ayrıca şu anda kullanılmayan kayıtların sayısı, recordsize vb gibi birçok özel değişken vardır unutmayın.

Ben bu kodu yerine:

fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+8);
$Value = trim(fread($this->Memo_Handle, $this->Memo_BlockSize));

Bu kod ile:

fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+4);
$Len  = unpack("N", fread($this->Memo_Handle, 4));
$Value = trim(fread($this->Memo_Handle, $Len[1] ));

Bu benim için yardımcı

Ben FoxPro kitaplıkları PHP vardır olası olduğunu düşünüyorum.

Sıfırdan kod gerekebilir. Byte-bilge okuma için, karşılamak fopen() fread() and colleagues.

Edit: Bir Visual FoxPro ODBC driver gibi görünüyor. PDO ve konektörü üzerinden bir FoxPro veritabanına bağlanmak mümkün olabilir. Nasıl başarı şansı, ve olurdu ne kadar iş, bilmiyorum.

Although not PHP, VFP is 1-based references and I think PHP is zero-based references so you'll have to decypher and adjust accordingly, but this works and hopefully you'll be able to post your version of this portion when finished.

FILETOSTR() in VFP will open a file, and read the entire content into a single memory variable as a character string -- all escape keys, high byte characters, etc, intact. You'll probably need to rely on an FOPEN(), FSEEK(), FCLOSE(), etc.

MemoTest.FPT was my sample memo table/file fpt1 = FILETOSTR( "MEMOTEST.FPT" )

İlk olarak, dosyanın oluşturulduğu zaman kullanılan MEMO blok boyutunu tespit etmek gerekir. Tipik olarak bu 64 bayt olurdu, ama link başına size yazı vardı.

Başlığı pozisyonları 6-7 (VFP 7 pozisyonları ve 8) boyutunu belirlemek. İlk bayt yüksek mertebe olduğunu

nBlockSize = ASC( SUBSTR( fpt1, 7, 1 )) * 256 + ASC( SUBSTR( fpt1, 8, 1 ))

Şimdi, bireysel kayıtlarına. DBF yapısı (ve tek bir kayıt yapısı gereği pek çok olabilir) not alanına sahip olursanız olun 4 bayt olacaktır. KAYIT alanda, içeriğin depolandığı not dosyasında "blok" tanımlar.

MemoBytes = sizin tespit alan yerde 4 bayt. Bu 0-255 ASCII olarak saklanır. Bu alan, düşük-düzen ve 256 ^ 3 = 16.777.216 olarak 4 byte olarak İLK bayt ile saklanır. Şimdiye kadar kullanılan ilk "Blok" memo başına 512 offset pozisyonunda başlayacak. Fpt dosyası spec başlığı kaplıyor 0-511 konumlandırır.

İlk not alan 8 gerçek 0x08 değil 0x38 "8" sayısı ve sıfır olan "8000" bir içerik varsa Yani, 0x00 vardır.

YourMemoField = "8000" (aslında ascii kullanmak, ama okunabilirlik gösteren onaltılık beklenen değer)

First Byte is ASCII value  * 1   ( 256 ^ 0 )
Second Byte is ASCII value * 256   (256 ^ 1)
Third Byte is ASCII value * 65536   (256 ^ 2)
Fourth Byte is ASCII value * 16777216 (256 ^ 3)

nMemoBlock =  byte1 + ( byte2 * 256 ) + ( byte3 * 65536 ) + ( byte4 * 16777216 )

Şimdi, için) (fseek gerekir

FSEEK( handle, nMemoBlock * nBlockSize +1 )

Aradığınız bloğunun ilk byte için. Bu BLOK başlığına işaret eder. Bu durumda, spec göre, ilk 4 bayt, ikinci 4 bayt içeriğin uzunluğu, blok İMZASI belirlemek. Bu iki, bayt ilk YÜKSEK-BYTE ile saklanır.

Lütfen fseek itibaren (), yüksek bayt yukarıda nMemoBlock onun TERS. "Bayt 1-4" burada fseek () pozisyonu vardır

nSignature = ( byte1 * 16777216 ) + ( byte2 * 65536 ) + ( byte3 * 256 ) + byte4

nMemoLength = ( byte5 * 16777216 ) + ( byte6 * 65536 ) + ( byte7 * 256 ) + byte8

Şimdi, fseek () 9. byte (sadece imza ve not uzunluğu için okuma başlığının 8 bayt SONRA verilerin 1. gerçek karakter) için. Bu veri başlangıcıdır.

Şimdi, içeriğin kalanını okumak ...

FSEEK() +9 characters to new position

cFinalMemoData = FREAD( handle, nMemoLength )

Ben bu mükemmel olmadığını biliyorum, ne de PHP komut dosyası, ama umarım onun işler nasıl depolandığı üzerinde pseudo-kod yeterli ve iyi yolda sizi alır.

Eğer 0 veya 1 ofset temelini sağlamak için hata ayıklama sürecinde adım gibi yine dikkate almak LÜTFEN. Basitleştirmek yardımcı olmak ve bu test etmek için, 2 alanları ... karakter alan ve bir not alanı ile basit. DBF, tüm içeriği onaylamak için birkaç kayıtları ve bazı temel içeriği, pozisyonları, vb eklendi yarattı

FPT dosyası not verileri içerir. DBF Eğer tip notun sütun var ve bu sütundaki bilgiler FPT dosyasında girişine bir göstericidir.

Eğer tablodan veri sorgulama iseniz, yalnızca verileri almak için not sütun başvurmak zorunda. Sen ayrı FPT dosya üzerinden veri ayrıştırmak gerekmez. OLE DB sürücüsü (veya dosyalarınızı VFP 6 veya daha önceki eğer ODBC sürücüsü), sadece size bu bilgiyi vermelidir.

Otomatik olarak MySQL için Visual FoxPro veri göç edecek bir aracı yoktur. Eğer biraz zaman kaydedebilirsiniz görmek için bunu kontrol etmek isteyebilirsiniz:

http://leafe.com/dls/vfp git

ve göç ile yardımcı araçlar için veri ve "VFP2MySQL Veri Yükleme programı" yapıları göç aracı için "Stru2MySQL_2" için arama.

Rick Schummer VFP MVP

Ayrıca DBF dosyaları ile oldukça iyi PHP dbase libraries.They çalışmalarını kontrol etmek isteyebilirsiniz.