举例来说

作者

温可维尔萨洛维奇

接触

在VIKOO.CL

最后更新

2005-12-12

注解

从7.4.0版本开始,PHP 7可以通过MapServer的 SWIG API . 我们鼓励MapServer用户使用SWIG API通过MapScript连接到PHP 7。本文档仅涵盖对遗留MapScript的支持;有关php7mapscript的最新示例,请参见 MS4W wiki 因为用户已经在那里贡献了PHP 7 mapscript脚本。

介绍

本文件旨在逐步解释 PHP映射脚本API 每一个都有实际的例子。它被假定为 MAP 和mapserver,并熟悉 PHP (scripting)HTML (markup) 语言。此文档最初是为MapServer v4.0创建的,但示例仍然适用于较新的版本。

我们开始吧…。

你好,好心的读者。我是图特,谢谢你下载我。对不起,我只是一本技术手册,所以我不能回答任何问题。维修人员,一个英俊,非常好和懒惰的家伙,根据我从屏幕的另一边看到的,也许可以回答你的问题。我现在在这里告诉您关于mapscript在其php化身中的情况。在我目前的年龄,我对初学者比高级用户更有用,尽管我希望有一天我会足够老,能够对高级mapscript程序员有用。

希望我活得够久…叹息。

但我的个人问题已经够多了,让我自己开始吧。我的职责是让您熟悉mapscript,尤其是php mapscript。当我结束时,您应该了解mapscript是什么,并且能够编写应用程序来显示和导航,即通过Web浏览器缩放和平移形状文件。

以下是您在陪同我完成余下的旅程之前必须肯定回答的问题(我为我的维护者缺乏文学品味而道歉)。

你有没有在某个地方跑步…

  • 一个能够将PHP作为CGI运行的Web服务器(Apache会这样做)?

  • PHP语言配置为CGI,4.1.2版或更高版本?我建议从4.3开始。

  • php mapscript,4.0版还是更高版本? php mapscript安装

你能。。。

  • 编码php或愿意 learn how to 是吗?

  • 写作和理解 HTML 文件?(请注意,javascript是一个加号)

  • 告诉别人到底什么是 shapefile [或 PostGIS 表?

此文档的大纲

  • 以独立于语言的方式概述mapscript

  • 一个微不足道的例子

  • 一个简单的例子

  • 结论

如果您想跳过某些部分,也可以直接通过位于顶部的目录转到每个部分。

MapScript概述

好吧,现在我终于到了我喜欢的地方。本概述旨在清除初学者在第一次面对mapscript时遇到的一些常见误解,并对mapscript的内部结构进行概述。现在,请看下面的图表(我再次为维护人员缺乏图形设计的品味而道歉)。

../../_images/phpmapscript-byexample-map.png

一切都始于网络上的一切。浏览器通过HTTP请求特定的URL。请求到达Web服务器,服务器依次传递文件或执行程序,然后将其输出返回浏览器。是的,我知道你知道,但是我被告知要尽可能完整,我会尽力的。

在mapscript的情况下,服务器执行一个特定的脚本,其中包含标准语言功能,也就是说,在没有mapscript的情况下,在该语言中具有的相同功能,加上对几乎所有mapserver c api的访问,mapserver api支持的完整性级别随您选择的语言而有所不同,但我认为它我的职责是告诉你几乎所有可用的mapscript风格都是可用的。这个API现在通过mapscript模块在脚本语言中公开,它允许您对空间数据执行许多类似于地理信息系统的操作,包括对形状文件的读写访问、数据的重投影以及许多其他操作。有关API的更多信息,请单击上面的链接。对于其他口味,您可以查看自己的文档,您会发现没有太大的区别。

运行mapscript应用程序不需要mapserver的cgi版本,就像运行cgi不需要特定的mapscript模块一样。CGI版本有许多现成的特性,mapscript只是一个API,所以对于mapscript,您必须从头开始,或者使用一些可用的示例。把CGI想象成一个直接用C语言编写的mapscript应用程序,可以直接访问mapserver c api。有时候开箱即用的功能有一些限制,这些限制可以被mapscript超越,但不能嵌入到CGI中。换句话说,CGI是不可脚本化的,但是您可以用mapscript来编程所有的CGI以及更多的CGI。这似乎是一个奇怪的事情要澄清,但是一个常见的误解,只要检查一下 list archives 如果你不愿意相信我。

与MAPServer本身一样,MAPScript只能使用 Mapfile 进行配置,但与CGI不同,它还包括动态创建地图或修改现有地图的可能性,以及将此信息与其他非地理信息系统数据源(如用户输入、非空间和空间数据)混合(这是MAPScript具有灵活性的关键)。数据库、文本文件等,您可以使用语言提供的每个模块。这种方法的威力是巨大的,最具限制性的是你的想象力。一如既往,灵活性伴随着价格、性能。通常使用脚本语言而不是C语言要慢一些,但现在这不应该是一个大问题。您仍然可以直接在C语言中编程(虽然您可能希望检查 mapserver-dev list )如果你愿意的话。

mapscript可以处理的输入和输出格式与构建mapserver/mapscript时配置的格式完全相同。但要记住的最重要的一点是,基本上,您将地理数据和相关的用户输入(例如单击地图图像)输入到mapscript,从而获得一个或多个文件,通常是标准图像文件,如png或jpeg。因此,您可以在任何服务器端脚本化Web应用程序、DHTML、Java小程序、CSS、HTML模板、会话中应用您所看到的任何东西。

我们的第一个申请

在第一个示例中,我将告诉您如何使用 Mapfile 在网页上显示形状文件。

Mapfile

这是 Mapfile :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    NAME "Europe in purple"
    SIZE 400 400
    STATUS ON
    SYMBOLSET "/var/www/html/maps/symbols/symbols.sym"
    EXTENT -5696501 1923039 5696501 11022882
    UNITS METERS
    SHAPEPATH "/var/www/html/maps/data"

    WEB
        IMAGEPATH "/var/www/html/maps/tmp/"
        IMAGEURL "/tmp/"
    END

    LAYER
        NAME "Europe"
        TYPE POLYGON
        STATUS ON
        DATA "europe"
        CLASS
            STYLE
                COLOR 110 50 100
                OUTLINECOLOR 200 200 200
                SYMBOL 0
            END
        END
    END

    END

这里我展示了一个单层的地图,其中europe.shp、europe.shx和europe.dbf文件必须位于名为data的子目录中。符号位于符号子目录中。所有这些位置都是相对于 Mapfile 所在的位置的,但我想这比对不起更安全。Web部分用于定义保存图像的位置和可用的URL。

用mapscript显示地图

要显示地图,将使用以下mapscript对象和方法:

  • MAPOBJ对象

  • ImageObj对象

MAPOBJ方法:

  • 构造器方法:mapobj ms_new mapobj(string map_file_name[,string new_map_path])

  • 绘制方法:imageobj draw()。

ImageObj方法:

  • saveWebImage方法:string saveWebImage()。

代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
    <?php

    dl('php_mapscript.so');

    $map_path="/var/www/html/ms/map_files/";

    $map = ms_newMapObj($map_path."europe.map");
    $image=$map->draw();
    $image_url=$image->saveWebImage();

    ?>

     <HTML>
      <HEAD>
          <TITLE>Example 1: Displaying a map</TITLE>
      </HEAD>
      <BODY>
          <IMG SRC=<?php echo $image_url; ?> >
      </BODY>
     </HTML>

我将通过本文档其余部分呈现的代码将遵循以下规则:

  • 每个非空行都有编号

此代码将呈现与shapefile europe对应的图像,并将其显示在HTML页上。

代码解释

  • 在第2行中,它加载了mapscript扩展名(如果您的php.ini文件配置为自动加载,则可能不需要它)。

  • 第3行声明一个保存 Mapfile 绝对路径的变量。

  • 第4行使用构造函数创建mapobj对象的实例。如您所见,构造函数接收 Mapfile 的位置作为其唯一必需的参数, Mapfile 接收到europe.map名称。

  • 然后调用映射对象的draw方法来渲染由 Mapfile (第5行)定义的图像。结果(imageobj)保存在$image变量中。

  • 第6行调用savewebimage方法来生成图像文件,它返回一个字符串,该字符串表示mapfile中定义的URL(在本例中为/tmp/filename.png)。

  • 其余的行是纯HTML,第13行除外,它定义图像的源URL将是存储在$image_url中的值。

您应该在系统上测试应用程序,以检查它是否真正工作,并在继续进行更复杂的示例之前解决特定配置中可能出现的问题。

产量

输出(使用欧洲形状文件)应如下所示:

../../_images/phpmapscript-byexample-map.png

缩放与平移

现在我将告诉您如何向代码添加缩放和平移功能。

下面是新方法和调用的对象的列表。

新对象:

  • 彭波托基

  • 雷克托布杰

调用的新方法和成员:

  • 映射对象的zoompoint方法:void zoompoint(int nzoomfactor、pointobj opixelpos、int nimagewidth、int nimageheight、rectobj ogeorefext)。

  • map对象的setextent方法:$map->setextent(double minx,double miny,double maxx,double maxy);。

  • 地图对象的范围、宽度和高度成员。

  • rectobj和pointobj的构造函数:$point=ms_newpointobj();$rect=ms_newrectobj();

  • 点对象的setxy方法:$point->setxy(double x_coord,double y_coord);

  • 矩形对象的setextent方法:$rect->setextent(double minx,double miny,double maxx,double maxy);

.map文件与上一个示例中显示的文件保持相同。

php/mapscript代码

在这里我介绍了新的代码。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    <?php

    dl('php_mapscript.so');

    // Default values and configuration

    $val_zsize=3;
    $check_pan="CHECKED";
    $map_path="/var/www/html/ms/map_files/";
    $map_file="europe.map";

    $map = ms_newMapObj($map_path.$map_file);


    if ( isset($_POST["mapa_x"]) && isset($_POST["mapa_y"])
          && !isset($_POST["full"]) ) {

          $extent_to_set = explode(" ",$_POST["extent"]);

          $map->setextent($extent_to_set[0],$extent_to_set[1],
                          $extent_to_set[2],$extent_to_set[3]);

          $my_point = ms_newpointObj();
          $my_point->setXY($_POST["mapa_x"],$_POST["mapa_y"]);

          $my_extent = ms_newrectObj();

          $my_extent->setextent($extent_to_set[0],$extent_to_set[1],
                                  $extent_to_set[2],$extent_to_set[3]);

          $zoom_factor = $_POST["zoom"]*$_POST["zsize"];
          if ($zoom_factor == 0) {
                  $zoom_factor = 1;
                  $check_pan = "CHECKED";
                  $check_zout = "";
                  $check_zin = "";
          } else if ($zoom_factor < 0) {
                  $check_pan = "";
                  $check_zout = "CHECKED";
                  $check_zin = "";
          } else {
                  $check_pan = "";
                  $check_zout = "";
                  $check_zin = "CHECKED";
          }

          $val_zsize = abs($zoom_factor);

          $map->zoompoint($zoom_factor,$my_point,$map->width,$map->height,
                          $my_extent);

     }


     $image=$map->draw();
     $image_url=$image->saveWebImage();

     $extent_to_html = $map->extent->minx." ".$map->extent->miny." "
                  .$map->extent->maxx." ".$map->extent->maxy;

     ?>
     <HTML>
     <HEAD>
     <TITLE>Map 2</TITLE>
     </HEAD>
     <BODY>
     <CENTER>
     <FORM METHOD=POST ACTION=<?php echo $HTTP_SERVER_VARS['PHP_SELF']?>>
     <TABLE>
     <TR>
          <TD>
                  <INPUT TYPE=IMAGE NAME="mapa" SRC="<?php echo $image_url?>">
          </TD>
     </TR>
     <TR>
          <TD>
                  Pan
          </TD>
          <TD>
                  <INPUT TYPE=RADIO NAME="zoom" VALUE=0 <?php echo $check_pan?>>
          </TD>
     </TR>
     <TR>
          <TD>
                  Zoom In
          </TD>
          <TD>
                  <INPUT TYPE=RADIO NAME="zoom" VALUE=1 <?php echo $check_zin?>>
          </TD>
     </TR>
     <TR>
          <TD>
                  Zoom Out
          </TD>
          <TD>
                  <INPUT TYPE=RADIO NAME="zoom" VALUE=-1 <?php echo $check_zout?>>
          </TD>
     </TR>
     <TR>
          <TD>
                  Zoom Size
          </TD>
          <TD>
                  <INPUT TYPE=TEXT NAME="zsize" VALUE="<?php echo $val_zsize?>"
                  SIZE=2>
          </TD>
     </TR>
     <TR>
          <TD>
                  Full Extent
          </TD>
          <TD>
                  <INPUT TYPE=SUBMIT NAME="full" VALUE="Go"
                  SIZE=2>
          </TD>
     </TABLE>
     <INPUT TYPE=HIDDEN NAME="extent" VALUE="<?php echo $extent_to_html?>">
     </FORM>
     </CENTER>
     </BODY>
     </HMTL>

此代码将缩小、放大、平移和完全还原上一示例中显示的图像。

看起来比实际情况复杂得多,很多行是HTML代码,剩下的大部分PHP代码只是处理表单等。

你应该先试试看它是怎么工作的。通过复制和粘贴代码,在您自己的服务器中进行尝试。

现在是时候让你玩一下了,看看你浏览器中的源代码,看看它是如何变化的。

完成?,现在让我们从HTML部分开始解释。

代码解释-HTML

第49行声明一个表单,第53行声明mapscript生成的图像是该表单的一部分,因此当您单击它时,单击的X和Y坐标(以像素为单位)将与其他数据一起发送,以供PHP代码处理。

如果您熟悉HTML和PHP,那么除了第98行之外,其余的HTML代码应该很容易理解,这将在适当的时候得到解释。

代码解释-php

现在看看PHP代码,它几乎是示例1中使用的相同代码,加上第9行到第37行。这些线是干什么的?

第9行检查表单中的相关变量是否已设置。mapa_x'和'mapa_y'表示单击图像的x和y坐标,“full”表示单击“full extent”按钮。

第一次显示页面时,if语句之间的代码没有执行,但其余的代码执行。第40行和第41行将“$extent”设置为“html”变量,并将 Mapfile 中定义的范围值用空格分隔;该值将放入第98行的html变量“extent”。

现在看第11行和第12行。我们在if语句中,这意味着表单至少已经提交了一次。我们获取存储在代码前一次执行中的范围(“extent”html变量),并将映射的范围设置为最后一个范围。这允许缩放或平移上一个范围,而不是 Mapfile 中设置的范围。

从最后一段中,您可以推断出所有默认值都设置在 Mapfile 中,并且必须以某种方式存储通过mapscript更改并希望保留在代码中的任何内容。在这种情况下,它是通过表单中的隐藏变量完成的。对于更高级的应用程序,可以使用会话变量或数据库。

现在,您应该能够看到“完全扩展”按钮的工作原理。如果您检查第10行,它会说如果您没有按下按钮,跳过if语句中的代码,那么范围将重置为 Mapfile 的值。您还应该看到它不一定是完整的范围(如果 Mapfile 中的范围不是完整的范围)。

第14行和第15行声明一个新的点对象,并用用户单击的值初始化它。您不应该忘记这些值是以像素为单位的,而不是以地理坐标为单位的。

第16行到第18行创建一个新的矩形对象,并使用上一个图像的范围对其进行设置,就像在第12行中一样。事实上,这也会起作用:$my_extent=$map->extent;。

要进行所有的缩放和平移,第35行调用了zoompoint函数,但首先必须准备好它接收到的参数。您可以确定用户单击的点,以及图像的范围(分别是my-point和$my-extent),但现在您必须确定缩放系数。这就是19到33行所做的。如果您想知道为什么单选按钮的值为0、-1和1,用于平移、放大和缩小,那么现在您将知道原因了。

缩放系数为1表示缩放点操作为平移,负值表示缩小,正值表示放大。因此,通过将接收到的单选按钮值(HTML变量“zoom”)乘以用户输入的缩放大小,就可以计算出缩放系数。如果该值为0,则表示用户选择了平移操作,因此“$zoom_factor”设置为1,否则乘法的结果是需要接收的缩放因子zoompoint。其他行用于保留用户下次单击的按钮。第34行试图保留用户输入的缩放大小值(它不会一直这样做,何时以及为什么该行失败?这是你要知道的)。

最后,第34行使用获得的缩放因子调用zoom point方法,即根据像素坐标构建的点(我坚持这个问题,因为zoom point几乎是接收像素坐标的唯一方法,对于其他方法,您必须自己将像素转换为地理参考坐标),i的高度和宽度法师,和范围。

调用zoompoint后,图像的范围将根据所执行的操作(或者,更好地说,缩放系数)进行相应的更改。然后绘制图像并保存当前范围(缩放后),以便在下一次迭代中使用。

结论

好吧,我该去给电池充电了。所以我会用最后的能量来分享最后的话。我在这里介绍的例子非常基本,但是你现在应该能够设计出改进它们的方法,并使之适合你的需要。请记住,您可以从通常可以通过PHP读取的任何源代码预处理、存储、读取、写入数据,以及MapServer可以处理的所有GIS数据源。您甚至可以使用PHP处理一些地理信息系统数据,前提是需要(SQL源就是一个很好的例子)。您还可以使用混合方法,其中一些脚本准备数据,然后通过到MapServer的CGI接口显示这些数据,或者基于GPS的输入动态创建数据,等等。这种可能性太多,无法完全枚举。正如我已经说过的,你的想象力是极限。本文档的下一个版本将包括包含多个层、具有不同数据源(不只是形状文件)和创建动态层和类的示例。如果你有更好的主意,或者想先在这里看看其他的东西,请给我的维修人员写张便条。

同时,如果您需要更大的示例,您可以参考原始的“GMAP演示”(您可以下载源代码 hereMapTools site (对于较旧的maplab,是基于phpmapscript构建的变色龙应用程序)。再见,谢谢你读到这里。