用file_get_contents来进行POST?很妖吧。
我也没有想到还有这种妖的东西。在向东的博客上看到这个的:http://www.xiangdong.org/blog/post/1623/
回忆未来?别惊讶,用他的话来说是山寨D。
原文:
file_get_contents.php: Post数据
PHP代码
- <?php
- function Post($url, $post = null)
- {
- $context = array();
-
- if (is_array($post))
- {
- ksort($post);
-
- $context['http'] = array
- (
- 'method' => 'POST',
- 'content' => http_build_query($post, '', '&'),
- );
- }
-
- return file_get_contents($url, false, stream_context_create($context));
- }
-
- $data = array
- (
- 'name' => 'test',
- 'email' => 'test@gmail.com',
- 'submit' => 'submit',
- );
-
- echo Post('http://localhost/5-5/request_post_result.php', $data);
- ?>
接收数据:
request_post_result.php 接收经过Post的数据:
PHP代码
- <?php
- echo $_POST['name'];
- echo $_POST['email'];
- echo $_POST['submit'];
- echo "fdfd";
- ?>
看一下,里面有一个特别的函数:stream_context_create,翻开手册看了一下,也没说什么呀,只是说:Creates and returns a stream context with any options supplied in options
preset.
而file_get_contents呢?它说:
Note: Context support was added with PHP 5.0.0. For a description of contexts, refer to Reference CLX, Stream Functions.
关于Stream Functions,手册上这么描述的。。。
A wrapper is additional code which tells the stream how to handle specific protocols/encodings. For example, the http wrapper knows how to translate a URL into an HTTP/1.0 request for a file on a remote server. There are many wrappers built into PHP by default (See Appendix O), and additional, custom wrappers may be added either within a PHP script using stream_wrapper_register(), or directly from an extension using the API Reference in Chapter 52. Because any variety of wrapper may be added to PHP, there is no set limit on what can be done with them. To access the list of currently registered wrappers, use stream_get_wrappers().
A stream is referenced as: scheme
://target
-
scheme
(string) - The name of the wrapper to be used. Examples include: file, http, https, ftp, ftps, compress.zlib, compress.bz2, and php. See Appendix O for a list of PHP built-in wrappers. If no wrapper is specified, the function default is used (typically file://).
-
target
- Depends on the wrapper used. For filesystem related streams this is typically a path and filename of the desired file. For network related streams this is typically a hostname, often with a path appended. Again, see Appendix O for a description of targets for built-in streams.
GET和POST接收编码格式不一样?说实话,原先没有考虑过这些问题。因为在一个项目中,程序的编码由项目开始到结束肯定都会一样的,当然在ajax处理的时候可能会有点变化。毕竟ajax的东西采用了UTF8进行传递。除此之外,其他的编码一般来说都是一致的。在看到这篇文章的时候,觉得不错。同时也是提醒一下自己需要注意。
因为他的代码是.NET的,临时转载,就不翻译成PHP了,看看别人的思路就行了。。。
原文地址:http://www.cnblogs.com/zhangziqiu/archive/2009/01/20/encoding.html
原文:
在查阅了一天资料,做了很多的试验, 精简提炼语言后, 完成了下面的文章.我发现在项目中太多的程序员对编码,尤其是Web程序中的中文参数编码一知半解.本文将作为一种规范提出, 以后将会应用到我制作的项目中.希望能够对大家有所启示.
[参数编码规范]
[原则]
避免在get或者post参数时直接传递中文字符.每次都经过指定格式的url编码后再传递.
[原因]
传递中文字符时,自动的编码解码格式和浏览器与服务器的设置有关.
测试Firefox3和IE6的Get方式发送中文参数, Firefox默认使用UTF-8格式编码中文参数, 而IE6即使在高级设置中设置了"总是以 UTF-8 发送URL", 仍然自动使用GB2312编码中文参数.
对于服务器端我们可以自由的控制解码的格式.但是往往是通过更改服务器配置进行全局的统一设置.比如对于ASP.NET程序.可以在Web.Config中设置服务器段的编码和解码格式:
XML/HTML代码
- <globalization culture="zh-CN" uiCulture="zh-CN" requestEncoding="UTF-8" responseEncoding="gb2312" />
但是我们没法控制浏览器端行为.用户可能使用不同的浏览器.
[解决方案]
一.统一默认的编码格式
1.设置服务器端的编码格式为UTF-8
2.传递参数全部进行编码,.服务器端(C#)使用Server.UrlEncode方法,客户端(javascript)使用encodeURIComponent方法.
说明:
客户端的javascript函数encodeURIComponent只能使用UTF-8编码格式. 所以需要设置服务器端request和response都为UTF-8.
缺陷是如果某些合作伙伴必须传递其他的编码格式的参数, 则服务器端或获取到乱码.此方案实现简单,适合大部分场景.
二.通过编码参数指定编码格式
为了解决可能存在的无法统一编码格式的问题, 我们使用一个参数"encoding"来显示的指定编码格式.encoding参数需要在所有的请求中传递,无论是get还是post.
1.对于javascript客户端编码而言, 仍然使用encodeURIComponent方法编码, 此时指定encoding参数的值为"UTF-8".
2.对于传入给服务器端的 其他编码格式, 比如GB2312, 我们不能使用默认的Request.Form或者QueryString方法进行编码.因为服务器端的编码格式可能设置为了UTF-8.此时使用 Request.Form或者QueryString会自动使用服务器端指定的编码格式进行解码. 所以需要使用下面的方法自己处理请求,获取参数:
C#代码
- /// <summary>
-
-
-
-
-
- public static NameValueCollection GetRequestParameters(HttpRequest request, string encode)
- {
- NameValueCollection result = null;
- Encoding destEncode = null;
-
-
- if (!String.IsNullOrEmpty(encode))
- {
- try
- {
-
- destEncode = Encoding.GetEncoding(encode);
- }
- catch
- {
-
- destEncode = null;
- }
- }
-
-
- if (request.HttpMethod == "POST")
- {
- if (null != destEncode)
- {
- Stream resStream = request.InputStream;
- byte[] filecontent = new byte[resStream.Length];
- resStream.Read(filecontent, 0, filecontent.Length);
- string postquery = destEncode.GetString(filecontent);
- result = HttpUtility.ParseQueryString(postquery, destEncode);
- }
- else
- {
- result = request.Form;
- }
- }
- else
- {
- if (null != destEncode)
- {
- result = System.Web.HttpUtility.ParseQueryString(request.Url.Query, destEncode);
- }
- else
- {
- result = request.QueryString;
- }
- }
-
-
- return result;
- }
此方法的返回值是一个NameValueCollection集合.客户端实例代码如下:
C#代码
- protected override void OnLoad(EventArgs e)
- {
- string sUrl = String.Empty;
- string tUrl = String.Empty;
- string encoding = String.Empty;
-
- Response.Clear();
-
- try
- {
-
- if (Request.HttpMethod.ToUpper().Trim() == "POST")
- {
- if (!String.IsNullOrEmpty(Request.Form["encoding"]))
- {
- encoding = Request.Form["encoding"].ToUpper();
- }
- }
- else
- {
- if (!String.IsNullOrEmpty(Request.QueryString["encoding"]))
- {
- encoding = Request.QueryString["encoding"].ToUpper();
- }
- }
-
-
- NameValueCollection paramList = EncodeUtility.GetRequestParameters(Request, encoding);
-
-
- sUrl = paramList["surl"];
- tUrl = paramList["turl"];
-
-
- if ( !( String.IsNullOrEmpty(sUrl) && String.IsNullOrEmpty(tUrl) ) )
- {
- Response.Write(OrderFromBL.OrderFromAnalysis(sUrl, tUrl));
- }
- }
- catch(Exception ex)
- {
- WebLog.CommentLog.CommonLogger.Error("OrderFromAjaxProxy.aspx页发生错误", ex);
- }
-
- Response.End();
- }
如果没有传入encoding参数,则使用服务器端默认的编码方式.
[总结]
两种解决方案首先都是要做到避免使用浏览器的中文自动编码, 中文参数一定要先编码再传递. 同时统一客户端和服务器端的编码格式.
[知识扩展]
[浏览器端的编码方式]
Get:
对于Get方式发送的请求, 不同的浏览器使用不同的编码方式自动为中文参数编码.比如:Firefox/3.0.5 使用UTF-8, IE6使用GB2312.
Post:
对于Post方式发送的 请求, 表单中的参数值对是通过request body发送给服务器,此时浏览器会根据网页的ContentType("text/html; charset=GBK")中指定的编码进行对表单中的数据进行编码,然后发给服务器。在HTML代码的Head中添加:
<meta http-equiv="Content-Type" content="text/html;charset=gb2312" />
Firefox/3.0.5 会使用根据charset中设置的编码格式编码post的中文参数.
IE6不起作用.
实验表明使用客户端浏览器默认编码格式具有不确定性.所以传递中文时我们要手工编码参数.
[Javascrip中的编码]
Javascrip语言中编码解码相关的方法主要有:
函数名称
|
函数说明
|
解释
|
escape()
|
escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串。
|
该方法不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。其他所有的字符都会被转义序列替换。
[已过时] 请使用 encodeURI() 或 encodeURIComponent()
|
unescape()
|
unescape() 函数可对通过 escape() 编码的字符串进行解码。
|
该函数的工作原理是这样的:通过找到形式为 %xx 和 %uxxxx 的字符序列(x 表示十六进制的数字),用 Unicode 字符 \u00xx 和 \uxxxx 替换这样的字符序列进行解码。
[已过时] 请使用 decodeURI() 或 decodeURIComponent()
|
encodeURI()
|
encodeURI() 函数可把字符串作为 URI 进行编码。
|
该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。
该方法的目的是对 URI 进行完整的编码,因此对以下在 URI 中具有特殊含义的 ASCII 标点符号,encodeURI() 函数是不会进行转义的:;/?:@&=+$,#
[提示] 如果 URI 的参数中含有不能转移的字符,则应当使用 encodeURIComponent() 方法分别对各参数进行编码。
|
decodeURI()
|
decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码。
|
|
encodeURIComponent()
|
encodeURIComponent() 函数可把字符串作为 URI 组件进行编码。
|
该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。
其他字符(比如 :;/?:@&=+$,# 这些用于分隔 URI 组件的标点符号),都是由一个或多个十六进制的转义序列替换的。
[提示] 此方法会编码URI中的特殊字符
|
decodeURIComponent()
|
decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码。
|
|
举例
document.write(encodeURIComponent("http://www.w3school.com.cn")+ "<br />")
document.write(encodeURI("http://www.w3school.com.cn")+ "<br />")
结果
http%3A%2F%2Fwww.w3school.com.cn
http://www.w3school.com.cn
总结
对于一个URI(URL也是一中URI),如果我们希望将它作为完整的网址发送请求, 但是上面带有中文, 则应该使用encodeURI方法.
如果是要编码参数,则应该使用encodeURIComponent.