wap开发FAQ

1. 开发WAP软件需要哪些工具?

为了开发WAP应用程序,需要一个WAP网关(注意:这里的网关可能是指支持WML的服务器。可以通过配置WWW服务器达到这个目的)和WAP工具包。工具包应当包括模拟器和能让开发者浏览WML网页。WML页
面的开发和HTML页面的开发一样,可以使用Notepad或者其他文本编辑器来进行编辑。

2. 有哪些公司现在提供这样的开发环境?

Nokia、Ericsson、UpPhone?和Motorola都提供免费的WAP网关和工具包。
Nokia:Nokia Toolkit和Nokia WAP Server。
Ericsson:Ericsson R320和WapIDE?
UpPhone?UpPhone? SDK。
Motorola:Motorola ADK。

3. 开发WAP应用一定要有WAP手机吗?

不是,当开发WAP应用的时候,不一定需要WAP手机。模拟器可以帮助开发者解决大部分的问题。但是如果是开发商业网站,特别是想知道各种移动电话在显示WML页面上的差别的时候,最好是配备一个。目前各种手机
对WML标记的支持和中文的支持状况大不相同,因此WAP手机还是必要的。

4. 开发者需要一个WAP网关吗?

不是很必要。如果只想进行简单的WAP内容服务,可以使用现有的Web服务器(只需要修改MIME类型)。移动电话会通过坐落在本地的网关连接到你的服务器上。
但是在网关上驻留开发者的程序有很多好处。既然开发者的程序是网关的一个部分,开发者就可以知道呼叫号码、身份、位置等等。

5. 可以看到WML的源代码么?

如果开发者使用SDK浏览的时候将能够看到WML的代码。如果只有一个HTML浏览器,可以访问“Fetch Page”服务(External Linkhttp://www.webcab.de)来取得代码。这个可以显示在Inter
net上的任何WML页面中。

6. 可能在WML中加入applets吗?

不能。
7. 可以使用HTML开发工具来开发WAP应用吗?

在大多数情况下开发工具是使用基于PC的浏览器。HTML、JavaScript?和Java对于WAP开发来说都没有用处。但是,越来越多的开发工具在加入对WML的支持。
Allair的Cold Fusion 4.5 和 HomeSite?已经有WML支持,虽然Allair也许需要清除一些BUG。另外PHP和ASP在Coldfusion/HomeSite?也能支持。
可以到 Marjolei Katsma的 HomeSite? Help site 上得到更多的信息。

8. 可以通过WML页面来操作数据库吗?

可以,与创建HTML页面相同。任何相关的服务器端的技术都可以用来生成WML页面。

9. 可以使用CGI生成WML页面吗?

当然。可以用创建HTML同样的方法来创建WML。如果想书写一个CGI来创建WML,只要记住在页面的开头正确设置MIME类型。具体的形式根据所使用的语言不同而不同。例如在Perl中:

print ("Content-type:application/vnd.wap.wml nnn"); 

注意至少要使用2个换行。

10. 如何使用Cold Fusion来生成页面?

使用Cold Fusion只需要加上:

<CFCONTENT type="text/vnd.wap.wml">

11. 如何使用PHP来书写动态的WML页面?

PHP(和大多数其他服务端脚本语言一样)可以被用来书写动态的WML内容。只需要将输出的标记限制在WML微型浏览器可接受的范围内。
注意PHP有很多内建的HTML功能,特别是错误功能,这些功能WML微型浏览器可能无法识别。
PHP同样可以在一个HTML文件中编写出既适合于HTML,也适合于WML的内容。PHP的源代码对于客户端来说是不可见的。因此可以针对HTML浏览器输出HTML页面,针对WML浏览器输出WML页面。
可以在开发PHP编写的WML页面的时候把以下代码加在开头:

<?

header("Content-type: text/vnd.wap.wml");
  echo("<?xml version="1.0"?>n");
echo("<!DOCTYPE wml PUBLIC "-
WAPFORUMDTD WML 1.1EN"
"External Linkhttp://www.wapforum.org/DTD/wml_1.1.xml">nn");
?>

基于PC的浏览器将忽略这些无法理解的WML标记。但是如果想在WAP设备或者模拟器上测试的时候,只需要将"
"去掉,页面自动变成WML页面。


12. 使用PHP动态输出WML
%php%
这些例子生成一个非常有用的应用叫做:PizzaCalc?。它将输入所有的pizza的帐单和人的数目,可以算出每个人的花费。
应用生成一个动态的页面叫做“calc”或者“input”。注意到所有的转义字符例如双引号。该页显示了一个简单的变量处理,和如何传递参数到另外的卡片:
使用WML浏览器就可以测试应用程序:
External Linkhttp://wap.colorline.no/wap-faq/apps/pizzacalc.html
或者输入:
External Linkhttp://wap.colorline.no/demos.html选择应用。

<?
header("Content-type: text/vnd.wap.wml");
echo("<?xml version="1.0"?>n");
echo("<!DOCTYPE wml PUBLIC "-WAPFORUMDTD WML 1.1EN"
"External Linkhttp://www.wapforum.org/DTD/wml_1.1.xml">nn");
echo("<!--The application PizzaCalc? was originally made by The Crusaders
www.crusaders.no on the Commodore Amiga -->n");
echo("<!-- It was unfortunately not possible to emulate the crap interger handling of the
original program -->n");
?>

<wml>
<?
  if($action n");     echo("n");     echo("n");     echo("n");     echo("

"calc") {     echo("<card id="result" title="PizzaCalc?">n");     echo("<do type="prev" label="Back">n");     echo("<go href="pizzacalc.html#input"/>n");     echo("</do>n");     echo("<p>n");     echo("The cost per eater will be ".$total / $eaters."<br/>n");   }   else {     echo("<card id="input" title="PizzaCalc?">n");     echo("<p>n"); echo("<anchor>Split Pizza bill <go href="pizzacalc.html?total=$(total)&eaters=$(eaters)&action=calc"/> </anchor>n");     echo("<br/>n");     echo("Total cost: <input type="text" name="total" format="*N"/>n");     echo("Eaters: <input type="text" name="eaters" format="*N"/>n");   } ?> </p> </card> </wml> %php% 13. 可以使用Java Servlet来生成WML页面吗? 当然。可以使用创建HTML同样的方法来创建WML。如果想书写一个CGI来创建WML,只要记住在页面的开头正确设置MIME类型: response.setContentType("text/vnd.wap.wml"); 14. 可以使用ASP、Perl等生成动态的应用吗? 是的。可以使用任何服务器端的脚本语言来生成WAP应用。 15. 如何使用ASP书写WML内容? ASP(Active Server Pages)可以做到和PHP一样,也可以用来书写动态的WML。如果需要一些好的例子请参考Luca Passani's WAP and ASP articles。或者查看Jean-Luc Praz's (jeanluc@corobori.com)。更多的ASP例子在:External Linkhttp://www.corobori.com/wap/。 16. 在使用ASP动态输出WML页面的时候,已经设置了Content-type,但是浏览器返回的仍然是text/html,有什么问题吗? 如果在ASP脚本中有一个错误,那么诊断程序会发还一个HTML页面,请检查脚本。 17. 在使用ASP生成WML页面的时候出现了错误: <MIME type "text/html" is not supported>,会是什么问题? 这个问题是Web浏览器不知道WML的正确类型,修改ASP的第一行,加入: <Response.ContentType? = "text/vnd.wap.wml">  后就可以工作了。 18. 下面的代码有什么问题吗? <%Response.ContentType? = "text/vnd.WAP.WML"%> <?xml version="1.0"?> 去掉<?xml version="1.0"?>之前的空格。XML解释器希望在这行中没有其他字符,甚至是空行。 19. ASP代码可以在模拟器上工作,在真正的浏览器上怎么不行? 在很多模拟器上没有像真正的WML浏览器那么严格。这些对于那些没有使用网关的模拟器(Nokia SDK/Toolkit)来说更是这样,有些就根本没有使用网关(WinWAP、WapMAN)。一个真正的WML浏览器应该只读取二进制的数据(从WML编码得来的)WMLC,对于网关应该将文本WML转换/编译成WMLC。语法是非常严格的。ASP是为HTML浏览器设置的,但是HTML没有WML那么严格。这里在ASP生成动态页面的时候有一个微小的“bug”。它在WML浏览器上不允许有任何地方输出白行(例如:空格,回车,换行)。注意到有些网关可能会修正这些问题,但有的则不管(例如:CMG网关)。下面是一个常见的ASP代码用来输出WML页面开头的MIME类型: <%Response.ContentType? = "text/vnd.wap.wml"%> <?xml version="1.0"?> 问题就在ASP将会在 .wml"%> 和 <?xml vers 之间输出换行和回车。这两行就被分割了。这将打乱WML代码的内容。WML必须以“<”开头,而且第一行是<?xml version="1.0"?>。就上面的WML页面回车/换行将会出现问题。最简单的解决办法是: <%Response.ContentType? = "text/vnd.wap.wml"%><?xml version="1.0"?> 在XML定义正确的格式化以后,后面的部分WML对空格就没有那么严格的要求。 要注意的是有些网关在输出ASP的时候会有问题,因此在WML代码中最好使用 Response.Write 而不是<%=MyVar?%>。 20. 如何使用Perl来生成WML内容? 和其他Server端程序一样。Perl也可以用来书写漂亮的WAP应用程序。最常见的就是如何使用Perl输出正确的MIME类型,下面的例子说明了这一点: print "Content-type: text/vnd.wap.wmlnn"; print "<?xml version="1.0"?>n"; print "<!DOCTYPE wml PUBLIC "-WAPFORUMDTD WML 1.1EN" "External Linkhttp://www.wapforum.org/DTD/wml_1.1.xml">n"; print "<wml>n"; …… 21. 应当如何下手书写WAP应用程序? 其实需要的只是Text编辑器。但是使用一个开发工具可以节约很多时间。在这之前应该浏览一下WAP的权威站点:www.wapforum.com。在Nokia WAP 开发论坛中进行注册,并且下载Nokia WAP Developer Toolkit 。Toolkit中的PDF文件可以给出一定的WML和WMLScript指导。Nokia To olkit需要JRE (Java Runtime Environment) v.1.2.2 或者更高版本。虽然工具可以用来为WAP设备设计应用,但是不是为专门的移动电话。在WAP开发工具上所看到的并不代表用户在手机上所看到的。为了确定想看到的事情,最好需要一个WAP设备,例如移动电话,或者模拟器。 Nokia WAP SDK 2有一个7110的模拟器。模拟器是一个有效的检测方式,能检测程序中的bug。 Nokia SDK 同样还包括一个小的WAP server让开发者可以从本地或者HTTP服务器上下载WML页面。到 Phone.com 开发站点注册后,Phone.com 提供UP.browser。这是最流行的浏览器,特别是在美国,Phone.com 提供UP.SDK。 在注册之后就可以下载。对于Ericsson R320 和 R380是最近的事情。应该注册并查看Ericsson's Developer's Zone 来得到开发工具。R380是一个非常好的模拟器,在 Symbian 不需要注册就可以下载。Ericsson 没有公开的为R320的模拟器。 Motorola 有一个平台叫做 Mobile Internet eXchange 或者 MIX 。Mobile Application Development Kit 已经开发出一个开发平台,即为 WAP也为Motorola的 VoxML?。在注册后,可以在下面的网址找到数据包。 External Linkhttp://www.motorola.com/MIMS/MSPG/cgi-bin/spn_madk.cgi.  WAPmine 是一个独立的应用,叫做 WAPPage 是一个所见即所得的编辑工具。而且有一个XML树型控件来编辑WML标签。如果在开发公共应用程序时,想在很多设备上测试你的程序,就像在不同的浏览器上测试HTML页面一样。注意在不同的WML浏览器上的差别,可能比在不同的HTML浏览器上的差别要大。 22. 如何编写和测试WML页面? 现在有很多SDK。AnywhereYouGo.com有WAP SDK和IDE列表,可以下载一个来用。任何文本编辑器都可以书写一个简单的WML页面,当然HTML编辑器也可以(特别是那些支持个人定义标签的),例如:Allaire Homesite (External Linkhttp://www.allaire.com )。可以使用SDK来做简单的测试,但是对于大的项目可能要困难些。AnywhereYouGo.com已经建立一套基于Web的工具来帮助WAP测试。 23. 哪儿可以在找到WML的测试工具? 首先确定WML代码是正确的,然后再使用WML测试工具。有一个非常好的测试工具在Zygo Communications(External Linkhttp://wap.z-y-g-o.com/tools/),测试工具是用Perl写的。里面还有其他的工具可供下载。 24. 如何操作WML页面? 操作WML页面或者卡片,最简单的办法是通过现有的网关。大多数移动电话提供者将功能都放在主页上,在上面可以通过WAP设备操作。网关的链接一般叫做“Go to URL”。当选择以后,WAP设备将通过网关操作指定的普通IP或者URL。在这种情况下,网关读取从WAP设备发送给网关的WML内容,就像PC浏览器读取内容的过程一样。有些营运商选择不让他们的用户操作其他的站点。这个就像Internet Service Provider只允许用户操作ISP自己的站点。像这样的做法是不明智的,这样会发现自己的用户去其他地方了。如果要坚持这种方法,可以通过ISP拨号或者使用一个公共的网关来取得其他的WAP资源。 25. 有没有一个友好的方式来管理WML内容? 还没有。虽然Oracale正在开发数据库驱动的文档服务,被称为Panama,可以支持WAP分发。 26. 如何防止用户代理cache页面? 如果用户使用ASP,应该加入一行<%Response.expires=-1%> ,这个将阻止Cache。 27. 怎样防止从Cache中读取WML页面? 当WML页面下载到WAP设备后,它将保存在WAP设备内存中一段时间,直到这个时间过期。在这之后,页面将从服务器下载,而不是从WAP设备的缓存读取。这个过程被称做Cache。但是有些时候不想让页面从缓存中读取,而是从服务器端读取。一个典型的例子就是当服务器的内容不断在更新的时候,通过在HTTP头中加入一定的cache信息,来告诉WAP设备该页面将不存储在缓存中。可以在服务器端生成HTTP头,或者使用PHP、ASP、Perl或者其他服务端开发语言。这一行不能被包括在页面里,既然是HTTP的信息头,就不是WML元素。对于静态页面,或许没有使用服务器端脚本语言,许多浏览器支持META标签来控制浏览器的Cache。看本部分的最后的例子。将下面代码加入到HTTP头中,页面将马上过期: Expires: Mon, 26 Jul 1997 05:00:00 GMT Last-Modified: DD. month YYYY InterWikiHH:MM:SS GMT Cache-Control: no-cache, must-revalidate Pragma: no-cache 第一行告诉微型浏览器,页面已经过期一段时间了。第二行告诉浏览器页面最后一次修改的时间。DD应该换成当天的日期,month YY HH MM SS等等类推。第三行和第四行有同样的效果。告诉浏览器页面不被 Cache(第三行适用于 HTTP 1.1,第四行适用于HTTP 1.0)。下面的是PHP的一个例子: <? set the correct MIME type      header("Content-type: text/vnd.wap.wml"); expires in the past      header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); Last modified, right now      header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");  Prevent caching, HTTP/1.1      header("Cache-Control: no-cache, must-revalidate"); Prevent caching, HTTP/1.0      header("Pragma: no-cache");    ?> 下面是使用WebClasses(VB)的例子。使用"Response.Expires=-1",防止Cache。  Private Sub WebClass_Start()       'Set correct MIME type       Response.ContentType? = "text/vnd.wap.wml"            'Make sure no caching       Response.Expires = -1       Response.AddHeader? "Pragma", "no-cache"       Response.AddHeader? "Cache-Control", "no-cache, must-revalidate"          'Use basicwml(my own) as template       Set NextItem? = basicwml   End Sub  这里有一个ASP的例子,同样使用“Response.Expires=-1”防止Cache。 <%     Response.ContentType? = "text/vnd.wap.wml"     Response.Expires = -1     Response.AddHeader? "Pragma", "no-cache"     Response.AddHeader? "Cache-Control", "no-cache, must-revalidate" %>  最后是使用META的例子: <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-WAPFORUMDTD WML 1.1EN" "External Linkhttp://www.wapforum.org/DTD/wml_1.1.xml">   <wml>     <head>       <meta forua="true" http-equiv="Cache-Control" content="max-age=0"/>     </head>     <card id="alwaysexpire">       <p>This deck will never be stored in the cache</p>     </card>   </wml> 下面的页面是在经过86400秒(24 hours)后过期。 <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-WAPFORUMDTD WML 1.1EN" "External Linkhttp://www.wapforum.org/DTD/wml_1.1.xml">   <wml>     <head>       <meta forua="true" http-equiv="Cache-Control" content="max-age=86400"/>     </head>     <card id="expire1day">       <p>This card will live in the cache for a day</p>     </card>   </wml> 有些浏览器例如:UP.Simulator如果可以通过“返回”达到另外一个卡片,那么它将不会重新装载卡片。为了强制这个更新动作,用户必须在META标签中使用must-revalidate 参数。 <meta forua="true" http-equiv="Cache-Control" content="must-revalidate"/> 28. 如何防止变量被保存在Cache中? 变量保存在Cache中,这样变量还可以再利用。例如当用户返回到上一个输入卡片,他不需要重新输入,只需要改变需要改变的地方。但是在某些情况下这会造成一些问题。例如以WAP聊天系统,有些变量用了一遍又一遍,但是需要不同的内容。有些浏览器,例如:Nokia 7110,就会存在类似的在该清除的时候无法清除的问题。在WML中,<card>标签有一个参数叫做newcontext。当newcontext="true" 时清除所有的变量。但是这样也清除了所有导航的历史记录,这意味着back按钮不再工作。为了清除变量,可以告诉浏览器将变量设为空: <setvar name="one_variable" value=""/> <setvar name="another_variable" value=""/> 但是,不是每个时候都有效果。在某些情况下必须使用一个难以想象的方法来清空变量。就是使用 onenterforward 事件。 <onevent type="onenterforward">    <refresh>      <setvar name="one_variable" value=""/>      <setvar name="another_variable" value=""/>    </refresh> </onevent> 29. 怎么能够知道请求是从WML浏览器来的还是HTML浏览器来的? 既然要利用已经存在的为HTML浏览器编写的代码,就需要知道请求是从HTML浏览器还是从WML浏览器过来的。同样地,如果想重新引导的HTML浏览器直接到相应的HTML文档上,WML浏览器到WML页面上,以下的PHP代码就可以做到这些。 <? Because this script sends out HTTP header information, the first characters in the file must be the <? PHP tag. relative URL to your HTML file    $htmlredirect = "/html/my_htmlpage.html"; ABSOLUTE URL to your WML file    $wmlredirect = "External Linkhttp://wap.mysite.com/wml/my_wmldeck.wml";    if(strpos(strtoupper($HTTP_ACCEPT),"VND.WAP.WML") > 0) { Check whether the browser/gateway says it accepts WML.      $br = "WML";    }    else {      $browser=substr(trim($HTTP_USER_AGENT),0,4);      if($browser

"Noki" || Nokia phones and emulators         $browser

"Eric" || Ericsson WAP phones and emulators         $browser

"WapI?" || Ericsson WapIDE? 2.0         $browser

"MC21" || Ericsson MC218         $browser

"AUR " || Ericsson R320         $browser

"R380" || Ericsson R380         $browser

"UP.B" || UP.Browser         $browser

"WinW?" || WinWAP? browser         $browser

"UPG1" || UP.SDK 4.0         $browser

"upsi" || another kind of UP.Browser ??         $browser

"QWAP" || unknown QWAPPER browser         $browser

"Jigs" || unknown JigSaw? browser         $browser

"Java" || unknown Java based browser         $browser

"Alca" || unknown Alcatel-BE3 browser (UP based?)         $browser

"MITS" || unknown Mitsubishi browser         $browser

"MOT-" || unknown browser (UP based?)         $browser

"My S" ||  unknown Ericsson devkit browser ? $browser

"WAPJ" || Virtual WAPJAG www.wapjag.de $browser

"fetc" || fetchpage.cgi Perl script from www.wapcab.de $browser

"ALAV" || yet another unknown UP based browser ?         $browser

"Wapa") another unknown browser (Web based "Wapalyzer"?)         {
        $br = "WML";
     }
     else {
       $br = "HTML";
     }
   }

   if($br == "WML") {
Force the browser to load the WML file instead
    header("302 Moved Temporarily");
    header("Location: ".$wmlredirect);
    exit;
   }
   else {
Force the browser to load the HTML file instead
    header("302 Moved Temporarily");
    header("Location: ".$htmlredirect);
    exit;
   }
  ?> 

这个判断是在服务端完成的, PHP代码将首先查看网关是否接收text/vnd.wap.vml MIME类型。如果不是,将检测前面的字符,查看是否为WML浏览器。如果不符合,那么就假设为HTML浏览器
。如果有新的WML浏览器,那么ID字符串也要增加。
这个代码基于Robert Whitinger(robert@wapsight.com)的代码,使用了Don Amaro(donamaro.concepcion@nl.unisys.com)提供的列表

注意:由于只需要四个字符串就可以辨别,因此例如:"WapIDE?-SDK/2.0;(R320s(Arial))" 可以使用“WapI?”来代替是可行的做法,也是足够的。
同样的功能也可以通过ASP来解决。先判断请求的是“/index.wml” 或者 “/index.html” 和所需要的MIME类型。另外以下的脚本辨别的方式和上面不一样。另外还需要网关告诉服务器它能
接收 的text/vnd.wap.wml MIME类型。该例子如下所示:

<%
Response.Buffer = TRUE
  Dim IsWap?
  httpAccept = LCase(Request.ServerVariables?("HTTP_ACCEPT"))
  if Instr(httpAccept,"wap") then
  IsWap?=1
  Else Response.Redirect "/index.html" : Response.Flush : Response.End
End if
%>
<%Response.ContentType? = "text/vnd.wap.wml"%><?xml version="1.0"?>
<%Response.Flush%>
<!DOCTYPE wml PUBLIC "-
WAPFORUMDTD WML 1.1EN"
"External Linkhttp://www.wapforum.org/DTD/wml_1.1.xml">
  <wml>
  <card id="redirect">
  <onevent type="onenterforward">
  <go href="/index.wml"/>
  </onevent>
  <p>
  <a href="/index.wml">enter</a>
  </p>
  </card>
  </wml>
  <%Response.InterWikiFlush:Response.End%>

30. 如何判断访问者是来自哪个浏览器或者移动电话?

可以通过检查HTTP_USER_AGENT标签来判断。例如试着使用Microsoft Internet Explorer访问一个站点的时候,HTTP_USER_AGENT将返回:Mozilla/4.
0 (compatible;MSIE 5.0; Windows 98);在同样的情况下使用Nokia 7110访问这个站点,HTTP_USER_AGENT就会是:Nokia7110?/1.0(04.73
)。据此可以判断用户代理是什么类型的。

31. 可以得到用户代理的电话号码吗?

不可以,除非网关支持这个特点,WAP没有办法知道用户的电话号码。

32. 可以通过WML使得可以用WAP设备进行拨号吗?

WAP的电话功能可以使用Wireless Telephony Application Interface(WTAI)。

例如:

WMLScript: WTAPublic.MakeCall?("9287787"); 

但是第一代的WAP设备不支持这个功能。

33. 能够从WAP设备中读取数据吗,例如:电话号码?

这里有一些通过HTTP的信息,但是十分有限。既然只有网关发送过来少量的信息,像WAP设备的号码可能无法读取。同时,在某些国家这还涉及到个人隐私的问题。
基本上丢弃的内容就是WAP网关传送给HTTP服务器的内容。这不同于WAP网关到网关。Phone.com的UP.Link网关是一个最好的例子。因为它在HTTP头中返回一个字符串叫做 UP_X_SUBN
O,里面包含了电话号码。Ericsson网关将传送一个辨别设备用的字符串,但是在明文中没有电话号码。
每次WAP设备向HTTP服务器请求一个URL,WAP网关就会将信息传送给HTTP服务器。
以下的PHP脚本显示了从网关过来的所有HTTP头的信息。可以使用WML浏览器进行测试。(External Linkhttp://wap.colorline.no/clientinfo.html)。其他的例子也可以在下面的UT
L中找到:External Linkhttp://wap.colorline.no/demos.html
第一个部分是取得所有的标准HTTP头信息。第二个部分是提取一个内容。

<?
  header("Content-type: text/vnd.wap.wml");
  echo("<?xml version="1.0"?>n");
echo("<!DOCTYPE wml PUBLIC "-WAPFORUMDTD WML 1.1EN"
"External Linkhttp://www.wapforum.org/DTD/wml_1.1.xml">nn");
  echo("<!—Code written in Microsoft NOTEPAD.EXE à n");
?>

<wml>
  <card id="init" title="Client Info">
    <p>
      <?
       
First part – standard HTTP stuff
        $headers = getallheaders();
        while (list($header, $value) = each($headers)) {
          echo strtoupper($header). ": ". $value. "<br/>n";       
        }
        Second part

IP address of the client side
        echo("REMOTE_ADDR: ".$REMOTE_ADDR. "<br/>n");
Port at the client side
        echo("REMOTE_PORT: ".$REMOTE_PORT. "<br/>n");
Name of authenticated user
        echo("REMOTE_USER: ".$REMOTE_USER. "<br/>n");
Gateway Interface type
        echo("GATEWAY_INTERFACE: ".$GATEWAY_INTERFACE. "<br/>n");
Protocol used by the server
        echo("SERVER_PROTOCOL: ".$SERVER_PROTOCOL. "<br/>n");
Request Method
        echo("REQUEST_METHOD: ".$REQUEST_METHOD. "<br/>n");
Connection type
        echo("HTTP_CONNECTION: ".$HTTP_CONNECTION. "<br/>n");
Host it connected via (proxy)
        echo("HTTP_VIA: ".$HTTP_VIA. "<br/>n");
      ?>
    </p>
  </card>
</wml> 
Henrik Gemal (gemal@dk.net)也有一个在线的基于WML的工具BrowserSpy?,来显示更多关于HTTP头的信息、服务器环境和用户的浏览器等等。有关这个工具的详细情况可以浏览h
External Linkttp://wap.gemal.dk/
Werner Forkel 提交了一个Perl的脚本,可以显示电话号码(如果有)。可以在以下位置测试:External Linkhttp://wap.colorline.no/wap-faq/apps/subnotest.w
ml,同样也收集在:External Linkhttp://wap.colorline.no/demos.html.
这些程序只适合某个网关。如果要测试其他的网关,可能就显示不出电话号码。因此电话号码不能作为ID号来处理。至少因为不是一个全球的标准。

34. 有没有办法连接到电话号码?

在某些情况下,当在显示了一连串的号码之后,需要中断功能连接到一个电话号码上并拨号。例如:执行一个 dial:12345678 就非常像 mailto: 标签。
越来越多的浏览器都支持这个功能,但还不是所有。Phone.com, Mitsubishi 和 Ericsson 已经在浏览器中集成了这个基于Wireless Telephony Interface
specifications (WTAI)的功能。 WTAI将允许以下的URL将关闭连接并且拨号:

  <go href="External Linkwtai://wp/mc;+4712345678">Make a call to +47-12345678</go> 

Nokia 7110 已经有个功能叫做“Use Number”。它可以通过WML卡片查找一个类似于电话号码的列表,然后用户可以选择进行呼叫。注意用户必须分离这些数字以便它能正常工作。

35. 使用GET或者POST方式能传送多少字符?

使用GET或者POST方式所能传送的字符数目,不同的设备有不同的限制。一个GET通过UTL传送变量,能传送的数据总量比使用POST方式所能传送的数据要小。例如,Nokia 7110似乎对每个GET 
限制在512个字节左右,但是POST最大可以达到一个编译后卡片的大小(约1300字节)。UP.SDK 4.0将GET请求限制在970左右,最大可以达到一个编译后卡片的大小。
显然,卡片有时候保存了要发送给服务器的参数的内容,既然编译后的卡片大小有限制,那么肯定要影响到整个所能传输的数据。
在POST和GET之间没有太多的区别。比如这个没有很好地使用GET的例子。

<input type="text" name="var1" format="*N"/>
   <p>
     <anchor>Send it
     <go href="somescript.cgi?variable=$(var1)" method="get"/>
     </anchor>
   </p>

下面仍然是一个使用GET的请求,但是使用了<postfield>来传送参数。这个代码就漂亮多了。既然可以定义为GET,同样也很容易转成POST。

<input type="text" name="var1" format="*N"/>
   <p>
     <anchor>Send it
     <go href="somescript.cgi" method="get">
       <postfield name="variable" value="$(var1)"/>
     </go>
     </anchor>
   </p>

直接改为POST:

<input type="text" name="var1" format="*N"/>
   <p>
     <anchor>Send it
     <go href="somescript.cgi" method="post">
       <postfield name="variable" value="$(var1)"/>
     </go>
     </anchor>
   </p>

最好是做测试找到到底能传输多少数据。这里有个测试程序:

External Linkhttp://wap.colorline.no/wap-faq/apps/putsize.php3

这个程序也可以在下面的URL中找到:External Linkhttp://wap.colorline.no/demos.html
该程序将产生一个卡片包含一个变量,里面包含了一定数量的字符X。用户可以选择传输是使用GET还是POST。在传输之后,脚本将要显示接收到的字符个数。
脚本生成一个页面来测试使用GET或者POST方式到底能发送多少个字符:

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-
WAPFORUMDTD WML 1.1EN"
"External Linkhttp://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
  <head>
  <meta forua="true" http-equiv="Cache-Control" content="max-age=0"/>
  <meta forua="true" http-equiv="Cache-Control" content="must-revalidate"/>
  </head>
  <card>
  <do type="prev" label="Back">
  <go href="putsize.php3"/>
  </do>
  <p>
  <anchor>GET data
  <go method="get" href="putsize.php3">
  <postfield name="a"
value="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"/>
  </go>
  </anchor>
  </p>
  </card>
</wml>

36. 如何同HTML站点一样POST/CGI,返回表单数据到服务器?

如果使用:

<go method="post" href="mycgi.cgi"> 

并且使用:

<postfield name="fieldname" value="$NameOfInputField?"/> 

就可以POST数据给CGI程序了。

37. POST无法工作是怎么回事?

有很多说POST参数将会丢失的流言,特别是在Nokia 7110。就笔者所知,还没有哪个Nokia 7110有这样的问题。这个问题主要是存在于网关或接收方。
测试显示Nokia SDK 2.18,当使用内建网关的时候,使用POST会出现问题。甚至当method 设置成“POST”的时候,服务器那边还是将POST请求作为 GET。
当使用POST的URL时 ,Nokia SDK 将会崩溃。在某些情况下URL的最后的字符将被删除。
POST Test页面将简单的POST的两个变量叫做“var1”和“var2”来显示整个变量的内容和HTTP头的内容。如果不能看到正确的变量内容,肯定有问题。检查HTTP头中的application
/x-www-form-urlencoded(注意!需要在变量中输入一些内容)。
这个方法解决了Nokia SDK 2.18的问题,可以把它配置到任意的公共网关来测试。笔者推荐使用 wapHQ 网关。
在其他的情况下,POST确实不工作,问题可能是HTTP头在服务器端解释的时候有问题。脚本语言,例如:ASP、Java或是CGI等等都是通过查看在HTTP头中的 application/x-www-f
orm-urlencoded 完全匹配的字符串。在某些情况下字符串可能有附加的数据,例如:charset="utf8" 。既然服务器端不是精确的匹配,它就不会查看HTTP头,因此POST就变量丢失了。

注意这不是浏览器的问题,在HTTP头加入字符集描述,将造成脚本语言方面的错误。
为了检测有关网关或浏览器的问题,仍使用上面的POST Test页面来测试。同样查看application/x-www-form-urlencoded 的输出,检查有没有附加的字符在结尾部分,如果有,
那么这就是服务器端的问题。
解决这个问题的方案很复杂,它随用户使用的脚本描述语言不同而不同,而且需要操作原代码。简单地说,解决方案就是需要人工读取HTTP头,不要使用脚本语言已经写好的读取方式。
这里有一个用ASP编写的解决方法。它显示了如何在POST中抓取数据。用户需要从二进制数据中发现需要的变量。

Dim lngToalByteCount
Dim vntRequestData

  lngTotalByteCount = Request.TotalBytes?
  vntRequestData = Request.BinaryRead?(lngTotalByteCount)

全部的代码,就应该像下面的代码:

<%@ Language=VBScript %>
<%
  Dim Temp, i, sPost, sWMLDeck

  'Converts the binary data to a string.
  For i = 1 To Request.TotalBytes?
    Temp = Request.BinaryRead?(1)
    sPost = sPost & Chr(AscB?(Temp))
  Next

  'Parses out the values of the POSTED variables (in this
  'example myvar1 and myvar2).
  Dim sVar1, sVar2
  sVar1 = getVar("myvar1", sPost)
  sVar2 = getVar("myvar2", sPost)

  'Writes the WML Deck displaying the POSTED Variables
  sWMLDeck = "<?xml version=1.0?>" & vbCrLf
  sWMLDeck = sWMLDeck & "<!DOCTYPE wml PUBLIC -//WAPFORUM//DTD WML 1.1//EN "
  sWMLDeck = sWMLDeck & "http://www.wapforum.org/DTD/wml_1.1.xml>" & vbCrLf
  sWMLDeck = sWMLDeck & vbCrLf & "<wml>" & vbCrLf & vbTab
  sWMLDeck = sWMLDeck & "<card id=main title=POST TEST>" & vbCrLf
  sWMLDeck = sWMLDeck & vbTab & vbTab & "<p>" & vbCrLf
  sWMLDeck = sWMLDeck & vbTab & vbTab & vbTab & "myVar1: " & sVar1 & "<br/>" & vbCrLf
  sWMLDeck = sWMLDeck & vbTab & vbTab & vbTab & "myVar2: " & sVar2 & vbCrLf
  sWMLDeck = sWMLDeck & vbTab & vbTab & "</p>" & vbCrLf & vbTab
  sWMLDeck = sWMLDeck & "</card>" & vbCrLf & ">/wml>"

  Response.ContentType? = "text/vnd.wap.wml"
  Response.Write(sWMLDeck)

  'Quick function for picking out the values of the POSTed variables.
  'sKey is the variable name, sRaw is the POST string.
  Private Function getVar(sKey, sRaw)
  Dim sRetVal
If InStr?(sRaw, sKey) Then
sRetVal = Mid(sRaw, InStr?(sRaw, sKey) + Len(sKey) + 1)
If InStr?(sRetVal, "&") Then
sRetVal = Mid(sRetVal, 1, InStr?(sRetVal, "&") - 1)
End If
End If
getVar = sRetVal
  End Function
%>

38. 为什么META标签不工作?

浏览器不支持默认的meta标签,例如:

<meta http-equiv="refresh" content="1;External Linkhttp://somewhere.com/"> 

虽然有少量网关支持非常有限的META标记。但是测试显示,如果使用了它们,网关就会出问题。例如某网关不支持普通的HTTP Cache控制,如果要实现Cache控制只好使用特殊的META标记。显然从其他
网关来的用户就可能不支持这个META。注意:不要使用META tags。肯定有其他的方式来完成你的想法。

最常使用的META是:

<meta http-equiv="refresh" content="1;External Linkhttp://somewhere.com/"> 

这个告诉浏览器重新装入指定的WML页面。WML中已经包含了一个<ontimer>。

39. 为什么服务器接收不到用户发送的参数?

用户输入的参数或者其他参数可以像在HTML中一样通过提交方式发送到服务器。在HTML中这个是<FORM>,POST或者GET。
首先知道要知道POST和GET的区别。对于POST浏览器将生成一个数据包将变量名和它们的内容捆绑在一起,并发送到服务器。对于GET,它其实是一个URL请求,变量名和内容都包含在URL中。
对于WAP环境,要求是非常严格的,必须要根据协议来操作。虽然以下的URL

"/cgi-bin/somescript?username=john&telephone=123-123-1234&occupation=banana+bender"

可以在HTML环境中工作,但是在WAP环境中无法工作。以上的部分编码将使得保护的变量内容被误解。特殊的空格(在 banana 和 bender )被转成 “+”。 URL就根本没有空格。
以上的URL在WAP中无法工作的主要原因是用来分割每个变量和变量内容的 & (与号)没有转义。正确的格式应该是:

"/cgi-bin/somescript?username=john&telephone=123-123-1234&occupation=banana+bender"

在这里 & 被名字实体所替换。为了解释更清楚些,请看下面的代码:

<card id="input" title="Gimme some data">
  <p><input type="text" name="username" format="M*m"/></p>
  <p><input type="text" name="occupation" format="M*m"/></p>
<p>
<anchor>Send this
<go href="/cgi-bin/somescript?username=$(username)
&occupation=$(occupation)"/>
</anchor>
</p>

注意这不是真正的WAP协议,专门的字符应该转义,否则将得到不可预料的结果。

40. 为什么在HTTP中的Referer看不见?

当HTML浏览器从一个URL到另外一个URL的时候,它默认地会发送一个叫做 Referer的 HTTP头给服务器,告诉它在浏览这个页面之前的那个页面。这是一个非常有用的特点,在WAP环境中同样也有。
但是既然这个信息来自用户代理(浏览器)、WAP设备,通常为了节约带宽和时间,就被省略了。
为了使用 Referer ,应该使用新的URL标签例如: <a>,<go>等等,并且加入参数:sendreferer。

<go href="/somedir/somedeck.wml" sendreferer="true"/> 

这样就会把参考的URL发送到服务器。

41. 如果没有找到URL,有可能重新将用户引导到另外一个WML卡片或者页面吗?

是的。但这是服务器端的特点,与客户端没有关系。

42. 为什么普通的HTTP 302重新导向不好使?

这的确是一个事实。核心的问题是在服务端的脚本语言,而不是在服务端语言和服务器之间。
所谓的302 Found HTTP反应是指服务器告诉用户代理,它所需要的资源在另外的地方可以找到。302反应可能包括一个人们可理解的信息,如果在这种情况下“ Content-type: ”就被设置了
。笔者所测试过的服务器,即使没有内容也都加了“Content-type:”。默认的 “Content-type:” 是text/html。当然有些网关不喜欢这个类型。
以下的例子已经经过测试,在Apache和Microsoft Internet Information Server都可以工作。如果使用其他的Web Server,或者其他的脚本语言,需要能转换这些简
单的脚本。关键的工作是十分简单的,除非需要,不用告诉服务器整个HTTP头。大多数Web Server将自动完成这个HTTP头,使得用户代理可以理解。
所有的代码例子可以在线测试。如果它们能够工作,用户将被重新引导到External Linkhttp://wap.colorline.no/clientinfo.html ,在那儿将产生一个WML页面来显示所有的HTTP头。
PHP 代码测试可以在 External Linkhttp://wap.colorline.no/wap-faq/apps/302test.php3中找到。

n");     echo("The cost per eater will be ".$total / $eaters."
n");   }   else {     echo("n");     echo("

n"); echo("Split Pizza bill n");     echo("
n");     echo("Total cost: n");     echo("Eaters: n");   } ?>

%php% 13. 可以使用Java Servlet来生成WML页面吗? 当然。可以使用创建HTML同样的方法来创建WML。如果想书写一个CGI来创建WML,只要记住在页面的开头正确设置MIME类型: response.setContentType("text/vnd.wap.wml"); 14. 可以使用ASP、Perl等生成动态的应用吗? 是的。可以使用任何服务器端的脚本语言来生成WAP应用。 15. 如何使用ASP书写WML内容? ASP(Active Server Pages)可以做到和PHP一样,也可以用来书写动态的WML。如果需要一些好的例子请参考Luca Passani's WAP and ASP articles。或者查看Jean-Luc Praz's (jeanluc@corobori.com)。更多的ASP例子在:http://www.corobori.com/wap/。 16. 在使用ASP动态输出WML页面的时候,已经设置了Content-type,但是浏览器返回的仍然是text/html,有什么问题吗? 如果在ASP脚本中有一个错误,那么诊断程序会发还一个HTML页面,请检查脚本。 17. 在使用ASP生成WML页面的时候出现了错误: ,会是什么问题? 这个问题是Web浏览器不知道WML的正确类型,修改ASP的第一行,加入:   后就可以工作了。 18. 下面的代码有什么问题吗?

去掉

之前的空格。XML解释器希望在这行中没有其他字符,甚至是空行。 19. ASP代码可以在模拟器上工作,在真正的浏览器上怎么不行? 在很多模拟器上没有像真正的WML浏览器那么严格。这些对于那些没有使用网关的模拟器(Nokia SDK/Toolkit)来说更是这样,有些就根本没有使用网关(WinWAP、WapMAN)。一个真正的WML浏览器应该只读取二进制的数据(从WML编码得来的)WMLC,对于网关应该将文本WML转换/编译成WMLC。语法是非常严格的。ASP是为HTML浏览器设置的,但是HTML没有WML那么严格。这里在ASP生成动态页面的时候有一个微小的“bug”。它在WML浏览器上不允许有任何地方输出白行(例如:空格,回车,换行)。注意到有些网关可能会修正这些问题,但有的则不管(例如:CMG网关)。下面是一个常见的ASP代码用来输出WML页面开头的MIME类型:

问题就在ASP将会在 .wml"%> 和

。就上面的WML页面回车/换行将会出现问题。最简单的解决办法是:

在XML定义正确的格式化以后,后面的部分WML对空格就没有那么严格的要求。 要注意的是有些网关在输出ASP的时候会有问题,因此在WML代码中最好使用 Response.Write 而不是

。 20. 如何使用Perl来生成WML内容? 和其他Server端程序一样。Perl也可以用来书写漂亮的WAP应用程序。最常见的就是如何使用Perl输出正确的MIME类型,下面的例子说明了这一点: print "Content-type: text/vnd.wap.wmlnn"; print "

n"; print "n"; print "n"; …… 21. 应当如何下手书写WAP应用程序? 其实需要的只是Text编辑器。但是使用一个开发工具可以节约很多时间。在这之前应该浏览一下WAP的权威站点:www.wapforum.com。在Nokia WAP 开发论坛中进行注册,并且下载Nokia WAP Developer Toolkit 。Toolkit中的PDF文件可以给出一定的WML和WMLScript指导。Nokia To olkit需要JRE (Java Runtime Environment) v.1.2.2 或者更高版本。虽然工具可以用来为WAP设备设计应用,但是不是为专门的移动电话。在WAP开发工具上所看到的并不代表用户在手机上所看到的。为了确定想看到的事情,最好需要一个WAP设备,例如移动电话,或者模拟器。 Nokia WAP SDK 2有一个7110的模拟器。模拟器是一个有效的检测方式,能检测程序中的bug。 Nokia SDK 同样还包括一个小的WAP server让开发者可以从本地或者HTTP服务器上下载WML页面。到 Phone.com 开发站点注册后,Phone.com 提供UP.browser。这是最流行的浏览器,特别是在美国,Phone.com 提供UP.SDK。 在注册之后就可以下载。对于Ericsson R320 和 R380是最近的事情。应该注册并查看Ericsson's Developer's Zone 来得到开发工具。R380是一个非常好的模拟器,在 Symbian 不需要注册就可以下载。Ericsson 没有公开的为R320的模拟器。 Motorola 有一个平台叫做 Mobile Internet eXchange 或者 MIX 。Mobile Application Development Kit 已经开发出一个开发平台,即为 WAP也为Motorola的 VoxML。在注册后,可以在下面的网址找到数据包。 http://www.motorola.com/MIMS/MSPG/cgi-bin/spn_madk.cgi.  WAPmine 是一个独立的应用,叫做 WAPPage 是一个所见即所得的编辑工具。而且有一个XML树型控件来编辑WML标签。如果在开发公共应用程序时,想在很多设备上测试你的程序,就像在不同的浏览器上测试HTML页面一样。注意在不同的WML浏览器上的差别,可能比在不同的HTML浏览器上的差别要大。 22. 如何编写和测试WML页面? 现在有很多SDK。AnywhereYouGo.com有WAP SDK和IDE列表,可以下载一个来用。任何文本编辑器都可以书写一个简单的WML页面,当然HTML编辑器也可以(特别是那些支持个人定义标签的),例如:Allaire Homesite (http://www.allaire.com )。可以使用SDK来做简单的测试,但是对于大的项目可能要困难些。AnywhereYouGo.com已经建立一套基于Web的工具来帮助WAP测试。 23. 哪儿可以在找到WML的测试工具? 首先确定WML代码是正确的,然后再使用WML测试工具。有一个非常好的测试工具在Zygo Communications(http://wap.z-y-g-o.com/tools/),测试工具是用Perl写的。里面还有其他的工具可供下载。 24. 如何操作WML页面? 操作WML页面或者卡片,最简单的办法是通过现有的网关。大多数移动电话提供者将功能都放在主页上,在上面可以通过WAP设备操作。网关的链接一般叫做“Go to URL”。当选择以后,WAP设备将通过网关操作指定的普通IP或者URL。在这种情况下,网关读取从WAP设备发送给网关的WML内容,就像PC浏览器读取内容的过程一样。有些营运商选择不让他们的用户操作其他的站点。这个就像Internet Service Provider只允许用户操作ISP自己的站点。像这样的做法是不明智的,这样会发现自己的用户去其他地方了。如果要坚持这种方法,可以通过ISP拨号或者使用一个公共的网关来取得其他的WAP资源。 25. 有没有一个友好的方式来管理WML内容? 还没有。虽然Oracale正在开发数据库驱动的文档服务,被称为Panama,可以支持WAP分发。 26. 如何防止用户代理cache页面? 如果用户使用ASP,应该加入一行

,这个将阻止Cache。 27. 怎样防止从Cache中读取WML页面? 当WML页面下载到WAP设备后,它将保存在WAP设备内存中一段时间,直到这个时间过期。在这之后,页面将从服务器下载,而不是从WAP设备的缓存读取。这个过程被称做Cache。但是有些时候不想让页面从缓存中读取,而是从服务器端读取。一个典型的例子就是当服务器的内容不断在更新的时候,通过在HTTP头中加入一定的cache信息,来告诉WAP设备该页面将不存储在缓存中。可以在服务器端生成HTTP头,或者使用PHP、ASP、Perl或者其他服务端开发语言。这一行不能被包括在页面里,既然是HTTP的信息头,就不是WML元素。对于静态页面,或许没有使用服务器端脚本语言,许多浏览器支持META标签来控制浏览器的Cache。看本部分的最后的例子。将下面代码加入到HTTP头中,页面将马上过期: Expires: Mon, 26 Jul 1997 05:00:00 GMT Last-Modified: DD. month YYYY HH:MM:SS GMT Cache-Control: no-cache, must-revalidate Pragma: no-cache 第一行告诉微型浏览器,页面已经过期一段时间了。第二行告诉浏览器页面最后一次修改的时间。DD应该换成当天的日期,month YY HH MM SS等等类推。第三行和第四行有同样的效果。告诉浏览器页面不被 Cache(第三行适用于 HTTP 1.1,第四行适用于HTTP 1.0)。下面的是PHP的一个例子:

下面是使用WebClasses(VB)的例子。使用"Response.Expires=-1",防止Cache。  Private Sub WebClass_Start()       'Set correct MIME type       Response.ContentType = "text/vnd.wap.wml"            'Make sure no caching       Response.Expires = -1       Response.AddHeader "Pragma", "no-cache"       Response.AddHeader "Cache-Control", "no-cache, must-revalidate"          'Use basicwml(my own) as template       Set NextItem = basicwml   End Sub  这里有一个ASP的例子,同样使用“Response.Expires=-1”防止Cache。

  最后是使用META的例子:

                         

This deck will never be stored in the cache

      下面的页面是在经过86400秒(24 hours)后过期。

                         

This card will live in the cache for a day

      有些浏览器例如:UP.Simulator如果可以通过“返回”达到另外一个卡片,那么它将不会重新装载卡片。为了强制这个更新动作,用户必须在META标签中使用must-revalidate 参数。 28. 如何防止变量被保存在Cache中? 变量保存在Cache中,这样变量还可以再利用。例如当用户返回到上一个输入卡片,他不需要重新输入,只需要改变需要改变的地方。但是在某些情况下这会造成一些问题。例如以WAP聊天系统,有些变量用了一遍又一遍,但是需要不同的内容。有些浏览器,例如:Nokia 7110,就会存在类似的在该清除的时候无法清除的问题。在WML中,标签有一个参数叫做newcontext。当newcontext="true" 时清除所有的变量。但是这样也清除了所有导航的历史记录,这意味着back按钮不再工作。为了清除变量,可以告诉浏览器将变量设为空: 但是,不是每个时候都有效果。在某些情况下必须使用一个难以想象的方法来清空变量。就是使用 onenterforward 事件。                 29. 怎么能够知道请求是从WML浏览器来的还是HTML浏览器来的? 既然要利用已经存在的为HTML浏览器编写的代码,就需要知道请求是从HTML浏览器还是从WML浏览器过来的。同样地,如果想重新引导的HTML浏览器直接到相应的HTML文档上,WML浏览器到WML页面上,以下的PHP代码就可以做到这些。

0) {// Check whether the browser/gateway says it accepts WML.      $br = "WML";    }    else {      $browser=substr(trim($HTTP_USER_AGENT),0,4);      if($browser">

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值