很多时候,我们想获得的内容或者想进行的操作,只有在登陆之后才有权限,此时就需要用到提交表单。
表单以HTML的形式呈现给用户,用户使用表单提交数据后,服务端获得表单数据进行处理,然后进行后续操作。比如我们登录的过程,登录的表单呈现给我们,输入用户名密码提交后,服务端获得用户名密码在数据库中查询,以查询结果判定密码正确与否。
向HTTP服务器提交数据常用的有GET和POST两种方法。下文针对这两种方法,结合实例说明curl的使用。
PHP程序
同前篇,服务端所有代码通过php实现。
- post.php,显示表单用于POST提交数据:
<html>
<head>
<title>
PHP POST Demo for curl basic usage By Stackeye
</title>
</head>
<body>
This is a post form demo.<br /><br />
<form action="welcome.php" method="post">
Name: <input type="text" name="name" />
Age: <input type="text" name="age" />
<input type="submit" />
</form>
<br /><br /><br />
<a href="http://www.stackeye.com" target="_blank">Stackeye's Blog</a>
</body>
</html>
- welcome.php,处理POST或GET的数据并显示:
<html>
<head>
<title>
PHP Form Demo for curl basic usage By Stackeye
</title>
</head>
<body>
This is a PHP Form Demo.<br />
It can parse both GET and POST data.<br />
This is a <strong>
if(count($_POST) > 0)
echo "POST";
else
echo "GET";
</strong> Request.<br /><br />
Welcome <strong>echo $_REQUEST["name"]; </strong>.<br />
You are <strong>echo $_REQUEST["age"]; </strong> years old.
<br /><br /><br />
<a href="http://www.stackeye.com" target="_blank">Stackeye's Blog</a>
</body>
</html>
跟踪表单提交的过程
提交表单的过程比GET网页的过程要复杂些。GET一个网页一般只会对Referer、User-Agent等字段进行限制。而提交表单的过程,需要知道提交的数据的字段名称、字段值的格式等。而且某些表单还含有隐藏字段。因此使用curl提交表单一般需要我们分析网页源代码,甚至采用抓包工具等进行数据包的分析。
我们分析的一般都是HTTP协议,chrome自带的Developer Tools可以更容易的分析HTTP协议,因此我们使用此工具(Firefox上的Firebug插件提供类似功能)。
以下分析基于chrome浏览器。Firefox浏览器需要自行安装firebug插件。
使用chrome打开网页(注意360急速浏览器下要使用“极速模式”,不要使用“兼容模式”),然后右键“审核元素”即可,如下图:
几个比较重要的tab页:
- Element标签用于显示当前元素,如想看到一个按钮的源码,对按钮右键审核元素即可看到。
- Network标签用于显示数据包,对于协议的分析,我们最常用此标签。
主要参数
1. -d/--data <data>
指定HTTP请求时发送的数据(主要为POST请求),使用和用户通过浏览器提交表单时一样的方式。使用的content-type是application/x-www-form-urlencoded
。
相当于--data-ascii
。发送纯粹二进制的数据(data purely binary),需要使用--data-binary
。URL-encode编码要发送的数据,需要使用--data-urlencode
。
当有多个-d时,curl会自动将发送的数据段是用“&”符号拼接,如:-d name=Stackeye -d age=100
将自动拼接为name=Stackeye&age=100作为post数据块(post chunk)发送。
如果想指定文件中的内容,可以使用-d @filename的形式。如文件foobar中内容为name=Stackeye
,使用-d @foobar即可达到-d name=Stackeye
一样的效果(只有第一个=作为特殊字符)。从文件读入时要注意=、@等特殊字符的异常情况。
而-d @-可以指定要发送的内容来自标准输入(stdin)。如执行curl -d @- http://127.0.0.1/welcome.php
,在终端输入数据后回车、Ctrl+D后达到相同效果。
对于文件的使用,对于其他类似选项适用。
但-d/--data
不会对数据进行url编码,而实际场景中我们最常用的还是发送url编码后的数据。
2. --data-urlencode <data>
使用URL-encode编码要发送的数据。除此之外,其余同-d。
-d选项默认是不会对要发送数据进行编码的,在旧版本没有--data-urlencode
选项的curl时,要发送编码的数据,必须手动对数据进行编码,或者将数据存放在编码的文件中。
比如要发送数据为”Stackeye blog”,必须手动把空格变为”%20”:
curl -d name=Stackeye%20blog -d age=100 http://127.0.0.1/welcome.php |
而--data-urlencode
自动完成此过程:
curl --data-urlencode name=Stackeye%20blog --data-urlencode age=100 \ |
wireshark抓包后显示如下:
在我们的程序中,直接使用-d发送需urlencode编码的数据(一般为除字母数字外的其他字符,如空格,汉字等),程序也会正常处理,那我们为什么还需要使用--data-urlencode
呢?原因如下:
- 能正常处理是apache服务器的原因。实际使用中服务器、程序语言不同,很可能出现无法处理不urlencode编码的数据,尤其是汉字和jsp程序,容易出现乱码
- 我们在使用浏览器操作时,浏览器会自动进行urlencode操作。为了尽可能逼真,我们使用
--data-urlencode
尽可能模仿浏览器的操作
--data-urlencode
同样可以使用@指定从文件中输入。而且可以使用name@filename
的形式。如使用--data-urlencode name@foobar
,文件foobar中内容为Stackeye,即可达到--data-urlencode name=Stackeye
的效果。这在-d选项中是不行的。需要注意的是此用法不会对name进行编码,所以需要预先编码好name字段。实际场景中一般name字段都是固定的,so it’s not too much trouble.
3. --data-binary <data>
发送指定的不做任何处理的数据(This posts data exactly as specified with no extra processing whatsoever),其余同-d。
4. -G/--get
和-d/–data、–data-binary一块使用时,表示强制使用GET的方式提交表单。
和 -I/–head 一块使用时,表示把提交的数据加在url中,而不是加在数据头中。
参数使用实例
1. POST
分析post.php可知,此php脚本提交了两个字段:name和age。
打开Developer Tools,填写表单提交后,可看到Network标签下显示出HTTP的POST数据包:
注意图中红圈处,可以在“view source”和”view parsed”直接切换,Request Header此时正以source模式显示,此模式下更利于我们的分析。
由此图可看到当前页面(post.php)向welcome.php提交了两个字段name和age,值分别为“Stackeye”和“100”,并可看到服务器的返回信息。
我们可使用curl命令的-d选项模拟此POST过程:
curl -s -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -o welcome.html \ |
或
curl -s -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -o welcome.html \ |
因为POST提交表单的过程,一定会有显示表单的页面,因此一般都会有来源页面。因此使用-e指定了post页面为来源页面。
分析可得到curl命令需要使用的几乎所有信息。
注:“几乎所有”的原因是如有些字段是在别的网页传递而来,或者由当前页面的js脚本等生成,此时就需要进一步的分析网页源代码等内容。
2. GET
GET的提交我们直接使用网址后面加参数的形式,使用浏览器打开如下网址:http://XXX.XXX.XXX.XXX/welcome.php?name=StackeyeGet&age=101
同样使用Developer Tools抓包分析如下:
由此图可看到GET向welcome.php提交了两个字段name和age,值分别为“StackeyeGet”和“101”。
我们可以使用curl的-G选项提交:
curl -s -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -o welcome.html \ |
此时可看到welcome.html中有“This is a GET Request.”表明是由GET提交数据。
实际场景中,表单中指定使用GET提交数据的情况很少。因此-G较少使用。
但我们更常用的还是直接curl带参数的url,此时与手动操作更接近:
curl -s -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" -o welcome.html \ |
总结
本篇主要为curl提交表单的相关命令参数。
实际应用中,我们可能还需要使用curl上传文件,相关命令请看下篇。