destnity
路人甲
路人甲
  • 注册日期2004-03-25
  • 发帖数341
  • QQ
  • 铜币272枚
  • 威望0点
  • 贡献值0点
  • 银元0个
阅读:2207回复:1

PHP写的 Shape File Reader

楼主#
更多 发布于:2004-07-16 17:42
<P>Shape File Reader<a href="attachment/2004-7/2004716174121184.zip">2004-7/2004716174121184.zip</a></P>
<P><?php
    /**
    * This class is under GPL Licencense Agreement
    * @author Juan Carlos Gonzalez Ulloa <<a href="mailtjgonzalez@innox.com.mx" target="_blank" >jgonzalez@innox.com.mx</A>>
    * Innovacion Inteligente S de RL de CV (Innox)
    * Av. Abraham Lincoln 28 B
    * Col. Vallarta Norte
    * Guadalajara, Jalisco. M閤ico.
    *
    * Class to read SHP files and modify the DBF related information
    * Just create the object and all the records will be saved in $shp->records
    * Each record has the "shp_data" and "dbf_data" arrays with the record information
    * You can modify the DBF information using the $shp_record->setDBFInformation($data)
    * The $data must be an array with the DBF's row data.
    *
    * Performance issues:
    * Because the class opens and fetches all the information (records/dbf info)
    * from the file, the loading time and memory amount neede may be way to much.
    * Example:
    *   15 seconds loading a 210907 points shape file
    *   60Mb memory limit needed
    *   Athlon XP 2200+
    *   Mandrake 10 OS
    */</P>
<P>    // Configuration
    define("SHOW_ERRORS", true);
    define("DEBUG", false);
    
    
    // Constants
    define("XY_POINT_RECORD_LENGTH", 16);
    
    
    // Strings
    define("ERROR_FILE_NOT_FOUND", "SHP File not found [%s]");
    define("INEXISTENT_RECORD_CLASS", "Unable to determine shape record type [%i]");
    define("INEXISTENT_FUNCTION", "Unable to find reading function [%s]");
    define("INEXISTENT_DBF_FILE", "Unable to open (read/write) SHP's DBF file [%s]");
    define("INCORRECT_DBF_FILE", "Unable to read SHP's DBF file [%s]");
    define("UNABLE_TO_WRITE_DBF_FILE", "Unable to write DBF file [%s]");
    
    // Global Arrays
    $record_class = array(0 => "RecordNull",
                          1 => "RecordPoint",
                          8 => "RecordMultiPoint",
                          3 => "RecordPolyLine",
                          5 => "RecordPolygon");</P>
<P>    class ShapeFile{
        var $file_name;
        var $fp;
        
        var $error_message = "";
        var $show_errors   = SHOW_ERRORS;
        
        var $shp_bounding_box = array();
        var $shp_type         = 0;
        
        var $records;
        
        function ShapeFile($file_name){
            $this->file_name = $file_name;
            _d("Opening [$file_name]");
            if(!is_readable($file_name)){
                return $this->setError( sprintf(ERROR_FILE_NOT_FOUND, $file_name) );
            }
            
            $this->fp = fopen($this->file_name, "rb");
            $this->_fetchShpBasicConfiguration();
            $this->_fetchRecords();
        }
        
// Data fetchers
        function _fetchShpBasicConfiguration(){
            _d("Reading basic information");
            fseek($this->fp, 32, SEEK_SET);
         $this->shp_type = readAndUnpack("i", fread($this->fp, 4));
         _d("SHP type detected: ".$this->shp_type);
        
         $this->shp_bounding_box = readBoundingBox($this->fp);
         //_d("SHP bounding box detected: miX=".$this->shp_bounding_box["xmin"]." miY=".$this->shp_bounding_box["ymin"]." maX=".$this->shp_bounding_box["xmax"]." maY=".$this->shp_bounding_box["ymax"]);
        }
        
        function _fetchRecords(){
            fseek($this->fp, 100);
            while(!feof($this->fp)){
                $shp_record = new ShapeRecord($this->fp, $this->file_name);
                if($shp_record->error_message != ""){
                    return false;
                }
                $this->records[] = $shp_record;
            }
        }
        
// General functions        
        function setError($error){
            $this->error_message = $error;
            if($this->show_errors){
                echo $error."\n";
            }
            return false;
        }
        
        function closeFile(){
            if($this->fp){
                fclose($this->fp);
            }
        }
        
        
    }
    
    
/**
* ShapeRecord
*
*/    
    class ShapeRecord{
        var $fp;
        var $dbf = null;
        
        var $record_number     = null;
        var $content_length    = null;
        var $record_shape_type = null;
        
        var $error_message     = "";
        
        var $shp_data = array();
        var $dbf_data = array();
        
        var $file_name = "";
        
        
        function ShapeRecord(;$fp, $file_name){
            $this->fp = $fp;
            _d("Shape record created at byte ".ftell($fp));
            
            $this->_readHeader();</P>
<P>            $function_name = "read".$this->getRecordClass();
            _d("Calling reading function [$function_name] starting at byte ".ftell($fp));
            
            if(function_exists($function_name)){
                $this->shp_data = $function_name($this->fp);
            } else {
                $this->setError( sprintf(INEXISTENT_FUNCTION, $function_name) );
            }
            $this->file_name = processDBFFileName($file_name);
            
            $this->_fetchDBFInformation();
        }
        
        function _readHeader(){
            $this->record_number     = readAndUnpack("N", fread($this->fp, 4));
            $this->content_length    = readAndUnpack("N", fread($this->fp, 4));
            $this->record_shape_type = readAndUnpack("i", fread($this->fp, 4));
            
            _d("Shape Record ID=".$this->record_number." ContentLength=".$this->content_length." RecordShapeType=".$this->record_shape_type."\nEnding byte ".ftell($this->fp)."\n");
        }
        
        function getRecordClass(){
            global $record_class;
            
            if(!isset($record_class[$this->record_shape_type])){
                return $this->setError( sprintf(INEXISTENT_RECORD_CLASS, $this->record_shape_type) );
            }
            return $record_class[$this->record_shape_type];
        }
        
        function setError($error){
            $this->error_message = $error;
            return false;
        }
        
        function getShpData(){
            return $this->shp_data;
        }
        
        function _openDBFFile($check_writeable = false){
            $check_function = $check_writeable ? "is_writable" : "is_readable";
            if($check_function($this->file_name)){
                $this->dbf = dbase_open($this->file_name, 2);
                if(!$this->dbf){
                    $this->setError( sprintf(INCORRECT_DBF_FILE, $this->file_name) );
                }
            } else {
                $this->setError( sprintf(INEXISTENT_DBF_FILE, $this->file_name) );
            }
        }
        
        function _closeDBFFile(){
            if($this->dbf){
                dbase_close($this->dbf);
                $this->dbf = null;
            }
        }
        
        function _fetchDBFInformation(){
//            print_r(stream_context_get_options($this->fp));
            $this->_openDBFFile();
            if($this->dbf) {
                $this->dbf_data = dbase_get_record_with_names($this->dbf, $this->record_number);
            } else {
                $this->setError( sprintf(INCORRECT_DBF_FILE, $this->file_name) );
            }
            $this->_closeDBFFile();
        }
        
        function setDBFInformation($row_array){
            $this->_openDBFFile(true);
            if($this->dbf) {
                unset($row_array["deleted"]);</P>
<P>                if(!dbase_replace_record($this->dbf, array_values($row_array), $this->record_number)){
                    $this->setError( sprintf(UNABLE_TO_WRITE_DBF_FILE, $this->file_name) );
                } else {
                    $this->dbf_data = $row_array;
                }
            } else {
                $this->setError( sprintf(INCORRECT_DBF_FILE, $this->file_name) );
            }
            $this->_closeDBFFile();
        }
    }
    
    
/**
* Reading functions
*/    
    
    function readRecordNull(;$fp, $read_shape_type = false){
        $data = array();
        if($read_shape_type) $data += readShapeType($fp);
        _d("Returning Null shp_data array = ".getArray($data));
        return $data;
    }
    $point_count = 0;
    function readRecordPoint(;$fp, $create_object = false){
        global $point_count;
        $data = array();
        
        $data["x"] = readAndUnpack("d", fread($fp, 8));
        $data["y"] = readAndUnpack("d", fread($fp, 8));
        
        //_d("Returning Point shp_data array = ".getArray($data));
        $point_count++;
        return $data;
    }
    
    function readRecordMultiPoint(;$fp){
        $data = readBoundingBox($fp);
        $data["numpoints"] = readAndUnpack("i", fread($fp, 4));
        _d("MultiPoint numpoints = ".$data["numpoints"]);
        
        for($i = 0; $i <= $data["numpoints"]; $i++){
            $data["points"][] = readRecordPoint($fp);
        }
        
        _d("Returning MultiPoint shp_data array = ".getArray($data));
        return $data;
    }
    
    function readRecordPolyLine(;$fp){
        $data = readBoundingBox($fp);
        $data["numparts"]  = readAndUnpack("i", fread($fp, 4));
        $data["numpoints"] = readAndUnpack("i", fread($fp, 4));
        
        _d("PolyLine numparts = ".$data["numparts"]." numpoints = ".$data["numpoints"]);
        
        for($i=0; $i<$data["numparts"]; $i++){
            $data["parts"][$i] = readAndUnpack("i", fread($fp, 4));
            _d("PolyLine adding point index= ".$data["parts"][$i]);
        }
        
        $points_initial_index = ftell($fp);
        _d("Reading points; initial index = $points_initial_index");
        $points_read          = 0;
        foreach($data["parts"] as $part_index => $point_index){
            //fseek($fp, $points_initial_index + $point_index);
            _d("Seeking initial index point [".($points_initial_index + $point_index)."]");
            if(!isset($data["parts"][$part_index]["points"]) || !is_array($data["parts"][$part_index]["points"])){
                $data["parts"][$part_index] = array();
                $data["parts"][$part_index]["points"] = array();
            }
            while(!in_array(ftell($fp), $data["parts"]) ;; $points_read < $data["numpoints"] ;; !feof($fp)){
                $data["parts"][$part_index]["points"][] = readRecordPoint($fp, true);
                $points_read++;
            }
        }
        
        fseek($fp, $points_initial_index + ($points_read * XY_POINT_RECORD_LENGTH));
        _d("Seeking end of points section [".($points_initial_index + ($points_read * XY_POINT_RECORD_LENGTH))."]");
        return $data;
    }
    
    function readRecordPolygon(;$fp){
        _d("Polygon reading; applying readRecordPolyLine function");
        return readRecordPolyLine($fp);
    }
    
/**
* General functions
*/    
    function processDBFFileName($dbf_filename){
        _d("Received filename [$dbf_filename]");
        if(!strstr($dbf_filename, ".")){
            $dbf_filename .= ".dbf";
        }
        
        if(substr($dbf_filename, strlen($dbf_filename)-3, 3) != "dbf"){
            $dbf_filename = substr($dbf_filename, 0, strlen($dbf_filename)-3)."dbf";
        }
        _d("Ended up like [$dbf_filename]");
        return $dbf_filename;
    }
    
    function readBoundingBox(;$fp){
        $data = array();
        $data["xmin"] = readAndUnpack("d",fread($fp, 8));
     $data["ymin"] = readAndUnpack("d",fread($fp, 8));
     $data["xmax"] = readAndUnpack("d",fread($fp, 8));
     $data["ymax"] = readAndUnpack("d",fread($fp, 8));
    
     _d("Bounding box read: miX=".$data["xmin"]." miY=".$data["ymin"]." maX=".$data["xmax"]." maY=".$data["ymax"]);
     return $data;
    }
    
    function readAndUnpack($type, $data){
        if(!$data) return $data;
        return current(unpack($type, $data));
    }
    
    function _d($debug_text){
        if(DEBUG){
            echo $debug_text."\n";
        }
    }
    
    function getArray($array){
        ob_start();
        print_r($array);
        $contents = ob_get_contents();
        ob_get_clean();
        return $contents;
    }
?>
</P>
喜欢0 评分0
签 名: 不能超过 250 个字符 文字将出现在您发表的文章的结尾处。
destnity
路人甲
路人甲
  • 注册日期2004-03-25
  • 发帖数341
  • QQ
  • 铜币272枚
  • 威望0点
  • 贡献值0点
  • 银元0个
1楼#
发布于:2004-07-16 17:43
没试过,不知道能不能用。大家有兴趣的做个参考吧。
签 名: 不能超过 250 个字符 文字将出现在您发表的文章的结尾处。
举报 回复(0) 喜欢(0)     评分
游客

返回顶部