解决跨浏览器下PHP下载文件名中的中文乱码问题 (2011-12-28)
PHP下载中文文件名文件,兼容各浏览器的方法
通过把Content-Type设置为application/octet-stream, 可以把动态生成的内容当作文件来下载,相信这个大家都会。 那么用Content-Disposition设置下载的文件名, 这个也有不少人知道吧。 基本上,下载程序都是这么写的:
$filename = "document.txt";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);
print "Hello!";
这样用浏览器打开之后,就可以下载document.txt。
但是,如果$filename是UTF-8编码的,有些浏览器就无法正常处理了。 比如把上面那个程序稍稍改一下:
$filename = "中文 文件名.txt";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $filename);
print "Hello!";
这样用浏览器打开之后,就可以下载document.txt。
把程序保存成UTF-8编码再访问,IE6下载的文件名就会乱码。 FF3下下载的文件名就只有“中文”两个字。Opera 9下一切正常。 输出的header实际上是这样子: Content-Disposition: attachment; filename=中文 文件名.txt其实按照RFC2231的定义, 多语言编码的Content-Disposition应该这么定义: Content-Disposition: attachment; filename*="utf8''%E4%B8%AD%E6%96%87%20%E6%96%87%E4%BB%B6%E5%90%8D.txt"即: filename后面的等号之前要加 * filename的值用单引号分成三段,分别是字符集(utf8)、语言(空)和urlencode过的文件名。 最好加上双引号,否则文件名中空格后面的部分在Firefox中显示不出来 注意urlencode的结果与php的urlencode函数结果不太相同,php的urlencode会把空格替换成+,而这里需要替换成%20 经过试验,发现几种主流浏览器的支持情况如下: IE6 attachment; filename="
最终解决办法:
$ua = $_SERVER["HTTP_USER_AGENT"];
$filename = "中文 文件名.txt";
$encoded_filename = urlencode($filename);
$encoded_filename = str_replace("+", "%20", $encoded_filename);
header('Content-Type: application/octet-stream');
if (preg_match("/MSIE/", $ua)) {
header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
} else if (preg_match("/Firefox/", $ua)) {
header('Content-Disposition: attachment; filename*="utf8\'\'' . $filename . '"');
} else {
header('Content-Disposition: attachment; filename="' . $filename . '"');
}
print 'ABC';
基于Comet服务器推技术 (2011-10-24)
最近一直关注COMET推技术,现在已经应用很普遍了
比如renren,新浪微博,都用到了COMET技术
大部分使用java实现的,下面是用PHP实现的原理
原理:利用htmlfile这个ActiveX,往页面上放一个iframe,设置它的src为请求的地址。

1.我们需要一个持久链接的HTTP请求
2.需要一个加载javascript的html页面
这个脚本会做一个无限循环,将返回服务器的时间,只要客户端连接。
<?php
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
flush();
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Comet php backend</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<script type="text/javascript">
// KHTML browser don't share javascripts between iframes
var is_khtml = navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML");
if (is_khtml)
{
var prototypejs = document.createElement('script');
prototypejs.setAttribute('type','text/javascript');
prototypejs.setAttribute('src','prototype.js');
var head = document.getElementsByTagName('head');
head[0].appendChild(prototypejs);
}
// load the comet object
var comet = window.parent.comet;
</script>
<?php
while(1) {
echo '<script type="text/javascript">';
echo 'comet.printServerTime('.time().');';
echo '</script>';
flush(); // used to send the echoed data to the client
sleep(1); // a little break to unload the server CPU
}
?>
</body>
</html>
创建客户端脚本
var comet = {
connection : false,
iframediv : false,
initialize: function() {
if (navigator.appVersion.indexOf("MSIE") != -1) {
// For IE browsers
comet.connection = new ActiveXObject("htmlfile");
comet.connection.open();
comet.connection.write("<html>");
comet.connection.write("<script>document.domain = '"+document.domain+"'");
comet.connection.write("</html>");
comet.connection.close();
comet.iframediv = comet.connection.createElement("div");
comet.connection.appendChild(comet.iframediv);
comet.connection.parentWindow.comet = comet;
comet.iframediv.innerHTML = "<iframe id='comet_iframe' src='./backend.php'></iframe>";
} else if (navigator.appVersion.indexOf("KHTML") != -1) {
// for KHTML browsers
comet.connection = document.createElement('iframe');
comet.connection.setAttribute('id', 'comet_iframe');
comet.connection.setAttribute('src', './backend.php');
with (comet.connection.style) {
position = "absolute";
left = top = "-100px";
height = width = "1px";
visibility = "hidden";
}
document.body.appendChild(comet.connection);
} else {
// For other browser (Firefox...)
comet.connection = document.createElement('iframe');
comet.connection.setAttribute('id', 'comet_iframe');
with (comet.connection.style) {
left = top = "-100px";
height = width = "1px";
visibility = "hidden";
display = 'none';
}
comet.iframediv = document.createElement('iframe');
comet.iframediv.setAttribute('src', './backend.php');
comet.connection.appendChild(comet.iframediv);
document.body.appendChild(comet.connection);
}
},
// this function will be called from backend.php
printServerTime: function (time) {
$('content').innerHTML = time;
},
onUnload: function() {
if (comet.connection) {
comet.connection = false; // release the iframe to prevent problems with IE when reloading the page
}
}
}
Event.observe(window, "load", comet.initialize);
Event.observe(window, "unload", comet.onUnload);
学习资料:
Comet:基于 HTTP 长连接的“服务器推”技术
http://www.ibm.com/developerworks/cn/web/wa-lo-comet/
How to implement COMET with PHP
http://www.zeitoun.net/articles/comet_and_php/start
PHP生成PNG图片,文字换行问题,和解析XML中带有CDATA数据 (2011-05-30)
出院后我负责开发的应用马上就要上线了
开发几天遇到这样几个问题,都解决了,以后在遇到类似的问题就不会这么麻烦了
以下是我实际应用中写的几个函数,可以重复利用 :)
问题一:
图片通过GD库生成会出现文字漂白问题,或者不显示,调试浪费了我半天的时间
合成图片颜色是真问题,困扰我很久最后解决了
原来imagecreate不支持更多的色彩
imagecreatetruecolor解决了这个问题
本函数需要 GD 2.0.1 或更高版本(推荐 2.0.28 及更高版本)。
-
/**
-
* @desc 创建结果图片
-
* @param
-
* @return file
-
*/
-
public function create_userimg() {
-
-
$user_name = addslashes($this->input->get('name'));
-
$user_name = urldecode($user_name);
-
$user_score = (int)$this->input->get('score');
-
-
if (preg_match("/^[x7f-xff]+$/", $user_name)) {
-
$user_name_len = mb_strlen($user_name);
-
$user_name_len = ceil($user_name_len/3);
-
$nickleft = 30+60*$user_name_len;
-
}else{
-
$user_name_len = strlen($user_name);
-
-
$nickleft = 120+13*$user_name_len;
-
}
-
-
$font = '.'.PATH_FONT.'/yahei.ttf';
-
$font_kaiti = '.'.PATH_FONT.'/SIMLI.TTF';
-
$size = 25;
-
-
//$bgimg = 'resource/default/images/lohas/result_bg.png';
-
$bgimg = 'resource/default/images/shishang/result_show.png';
-
$nick = 'resource/default/images/shishang/shishang_nick.png';
-
-
$im = @imagecreatetruecolor(506,432) or die("Cannot Initialize new GD image stream");
-
$white = imagecolorallocate( $im, 255, 255, 255 );
-
imagefill( $im, 0, 0, $white );
-
imagecopy($im, $this->Image, 0, 0, 0, 0, 506, 432);
-
-
$bgimg = imagecreatefrompng($bgimg);
-
imagecopy($im,$bgimg,0,0,0,0,506,432);
-
-
$nick = imagecreatefrompng($nick);
-
imagecopy($im,$nick,$nickleft,136,0,0,77,14);
-
-
-
$green=imagecolorallocate($im,68,160,28);
-
$hei=imagecolorallocate($im,0,0,0);
-
$bai=imagecolorallocate($im,255,255,255);
-
-
if (preg_match("/^[x7f-xff]+$/", $user_name)) {
-
imagettftext($im,'25',0,62,150,$hei,$font_kaiti,$user_name);
-
}else{
-
imagettftext($im,'21',0,62,150,$hei,$font,$user_name);
-
}
-
-
imagettftext($im,'12',0,70,209,$green,$font,$text_1);
-
-
imagettftext($im,'11',0,170,238,$green,$font,$text_2);
-
-
imagettftext($im,'12',0,360,210,$green,$font,$score);
-
-
imagettftext($im,'11',0,95,237,$green,$font,$user_vs);
-
-
imagettftext($im,'10',0,330,340,$hei,$font,$date_text);
-
-
-
-
header("Content-type: image/png");
-
imagepng($im);
-
imagedestroy($im);
-
}
问题二:
PHP中文换行问题,因为文字要写在图片里,类似css的自动换行,
php对英文有wordwrap()函数支持换行,但不支持中文,下面函数解决了PHP中文换行问题
-
/**
-
* @desc GD库生成图片中文自动换行
-
* 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度
-
* */
-
public function autowrap($fontsize, $angle, $fontface, $string, $width) {
-
$content = "";
-
-
// 将字符串拆分成一个个单字 保存到数组 letter 中
-
for ($i=0;$i<mb_strlen($string);$i++) {
-
$letter[] = mb_substr($string, $i, 1);
-
}
-
-
foreach ($letter as $l) {
-
$teststr = $content."".$l;
-
$testbox = imagettfbbox($fontsize, $angle, $fontface, $teststr);
-
// 判断拼接后的字符串是否超过预设的宽度
-
if (($testbox[2] > $width) && ($content !== "")) {
-
$content .= "n";
-
}
-
$content .= $l;
-
}
-
-
$content = mb_convert_encoding($content, "html-entities","utf-8" );
-
-
return $content;
-
}
问题三:
我在调用数据库接口的时候,取XML中的CDATA数据
解析XML中带有<!CDATA>问题,“ <name><![CDATA[Lois & Clark]]></name>”,
CDATA中的数据取不到值,simplexml_load_string函数解决问题
simplexml_load_string($response, SimpleXMLElement , LIBXML_NOCDATA);
-
/**
-
* @desc CURL提交XML返回食材库XMl数据
-
* @param STRING XML
-
* @return XML
-
*/
-
private function do_curl_post($xmldata){
-
-
$url = SITE_URL.$this->shicai_interface;
-
-
$header[] = "Content-type: text/xml";
-
$ch = curl_init();
-
curl_setopt($ch, CURLOPT_URL, $url);
-
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
-
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
-
curl_setopt($ch, CURLOPT_POST, 1);
-
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmldata);
-
$response = curl_exec($ch);
-
$response = simplexml_load_string($response, SimpleXMLElement , LIBXML_NOCDATA);
-
-
if(curl_errno($ch)){
-
print curl_error($ch);
-
}
-
curl_close($ch);
-
return $response;
-
}
使用JSONP实现跨域通信 (2011-03-29)
Asynchronous JavaScript and XML (Ajax) 是驱动新一代 Web 站点(流行术语为 Web 2.0 站点)的关键技术。Ajax 允许在不干扰 Web 应用程序的显示和行为的情况下在后台进行数据检索。使用 XMLHttpRequest 函数获取数据,它是一种 API,允许客户端 JavaScript 通过 HTTP 连接到远程服务器。Ajax 也是许多 mashup 的驱动力,它可将来自多个地方的内容集成为单一 Web 应用程序。
不过,由于受到浏览器的限制,该方法不允许跨域通信。如果尝试从不同的域请求数据,会出现安全错误。如果能控制数 据驻留的远程服务器并且每个请求都前往同一域,就可以避免这些安全错误。但是,如果仅停留在自己的服务器上,Web 应用程序还有什么用处呢?如果需要从多个第三方服务器收集数据时,又该怎么办?
同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这意味着浏览器隔离来自不同源的内容,以防止它们之间的操作。这个浏览器策略很旧,从 Netscape Navigator 2.0 版本开始就存在。
克服该限制的一个相对简单的方法是让 Web 页面向它源自的 Web 服务器请求数据,并且让 Web 服务器像代理一样将请求转发给真正的第三方服务器。尽管该技术获得了普遍使用,但它是不可伸缩的。另一种方式是使用框架要素在当前 Web 页面中创建新区域,并且使用 GET 请求获取任何第三方资源。不过,获取资源后,框架中的内容会受到同源策略的限制。
克服该限制更理想方法是在 Web 页面中插入动态脚本元素,该页面源指向其他域中的服务 URL 并且在自身脚本中获取数据。脚本加载时它开始执行。该方法是可行的,因为同源策略不阻止动态脚本插入,并且将脚本看作是从提供 Web 页面的域上加载的。但如果该脚本尝试从另一个域上加载文档,就不会成功。幸运的是,通过添加 JavaScript Object Notation (JSON) 可以改进该技术。
JSON 是用于在浏览器和服务器之间交换信息的轻量级数据格式(与 XML 相比)。JOSON 依赖于 JavaScript 开发人员,因为它是 JavaScript 对象的字符串表示。例如,假设有一个含两个属性的 ticker 对象:symbol 和 price。这是在 JavaScript 中定义 ticker 对象的方式:
var ticker = {symbol: 'IBM', price: 91.42};
|
并且这是它的 JSON 表示方式:
{symbol: 'IBM', price: 91.42}
|
从 参考资料 查找更多有关 JSON 和将其作为数据内部交换格式的信息。清单 1 定义了一个 JavaScript 函数,调用该函数时会显示 IBM 的股价。(我们没有详细介绍如何将该函数添加到 Web 页面)。
清单 1. 定义 showPrice 函数
function showPrice(data) {
alert("Symbol: " + data.symbol + ", Price: " + data.price);
}
|
可以将 JSON 数据作为参数传递,以调用该函数:
showPrice({symbol: 'IBM', price: 91.42}); // alerts: Symbol: IBM, Price: 91.42
|
现在准备将这两个步骤包含到 Web 页面,如清单 2 所示。
清单 2. 在 Web 页面中包含 showPrice 函数和参数
<script type="text/javascript">
function showPrice(data) {
alert("Symbol: " + data.symbol + ", Price: " + data.price);
}
</script>
<script type="text/javascript">showPrice({symbol: 'IBM', price: 91.42});</script>
|
加载页面后,应该看如图 1 所示的警告。
图 1. IBM ticker
至此,本文已展示了如何将静态 JSON 数据作为参数调用 JavaScript 函数。不过,通过在函数调用中动态包装 JSON 数据可以用动态数据调用函数,这是一种动态 JavaScript 插入的技术。要查看其效果,将下面一行放入名为 ticker.js 的独立 JavaScript 文件中。
showPrice({symbol: 'IBM', price: 91.42});
|
现在改变 Web 页面中的脚本,使其和清单 3 一样。
清单 3. 动态 JavaScript 插入代码
<script type="text/javascript">
// This is our function to be called with JSON data
function showPrice(data) {
alert("Symbol: " + data.symbol + ", Price: " + data.price);
}
var url = “ticker.js”; // URL of the external script
// this shows dynamic script insertion
var script = document.createElement('script');
script.setAttribute('src', url);
// load the script
document.getElementsByTagName('head')[0].appendChild(script);
</script>
|
在清单 3 所示的例子中,动态插入的 JavaScript 代码位于 ticker.js 文件中,它将真正的 JSON 数据作为参数调用 showPrice()函数。
前面已经提到,同源策略不阻止将动态脚本元素插入文档中。也就是说,可以动态插入来自不同域的 JavaScript,并且这些域都携带 JSON 数据。这其实是真正的 JSONP(JSON with Padding):打包在函数调用中的 JSON 数据。注意,为了完成该操作,Web 页面必须在插入时具有已经定义好的回调函数,也就是我们例子中的 showPrice()。
不过,所谓的 JSONP 服务(或 Remote JSON Service)是一种带有附加功能的 Web 服务,该功能支持在特定于用户的函数调用中打包返回的 JSON 数据。这种方法依赖于接受回调函数名作为请求参数的远程服务。然后该服务生成对该函数的调用,将 JSON 数据作为参数传递,在到达客户端时将其插入 Web 页面并开始执行。
从 1.2 版本开始,jQuery 拥有对 JSONP 回调的本地支持。如果指定了 JSONP 回调,就可以加载位于另一个域的 JSON 数据,回调的语法为:url?callback=?。
jQuery 自动将 ? 替换为要调用的生成函数名。清单 4 显示了该代码。
清单 4. 使用 JSONP 回调
jQuery.getJSON(url+"&callback=?", function(data) {
alert("Symbol: " + data.symbol + ", Price: " + data.price);
});
|
为此,jQuery 将一个全局函数附加到插入脚本时需要调用的窗口对象。另外,jQuery 也能优化非跨域调用。如果向同一个域发出请求,jQuery 就将其转化为普通 Ajax 请求。
在上一个例子中,使用了静态文件(ticker.js)将 JavaScript 动态插入到 Web 页面中。尽管返回了 JSONP 回复,但它不允许您在 URL 中定义回调函数名。这不是 JSONP 服务。因此,如何才能将其转换为真正的 JSONP 服务呢?可使用的方法很多。这里我们将分别使用 PHP 和 Java 展示两个示例。
首先,假设您的服务在所请求的 URL 中接受了一个名为 callback 的参数。(参数名不重要,但是客户和服务器必须都同意该名称)。另外假设向服务发送的请求是这样的:
http://www.yourdomain.com/jsonp/ticker?symbol=IBM&callback=showPrice |
在这种情况下,symbol 是表示请求 ticker symbol 的请求参数,而 callback 是 Web 应用程序的回调函数的名称。使用清单 5 所示的代码可以通过 jQuery 的 JSONP 支持调用该服务。
清单 5. 调用回调服务
jQuery.getJSON("http://www.yourdomain.com/jsonp/ticker?symbol=IBM&callback=?",
function(data) {
alert("Symbol: " + data.symbol + ", Price: " + data.price);
});
|
注意,我们使用 ? 作为回调函数名,而非真实的函数名。因为 jQuery 会用生成的函数名替换 ?。所以您不用定义类似于 showPrice() 的函数。
清单 6 显示了用 PHP 实现的 JSONP 服务的一段代码。
清单 6. 用 PHP 实现的 JSONP 服务的代码片段
$jsonData = getDataAsJson($_GET['symbol']);
echo $_GET['callback'] . '(' . $jsonData . ');';
// prints: jsonp1232617941775({"symbol" : "IBM", "price" : "91.42"});
|
清单 7 显示了具有同样功能的 Java™ Servlet 方法。
清单 7. 用 Java servlet 实现的 JSONP 服务
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String jsonData = getDataAsJson(req.getParameter("symbol"));
String output = req.getParameter("callback") + "(" + jsonData + ");";
resp.setContentType("text/javascript");
PrintWriter out = resp.getWriter();
out.println(output);
// prints: jsonp1232617941775({"symbol" : "IBM", "price" : "91.42"});
}
|
那么,如果要构建 mashup 应该怎么办,是从第三方服务器收集内容,并在单一的 Web 页面中显示它们吗?答案很简单:您必须使用第三方 JSONP 服务。这种服务并不少。
知道如何使用 JSONP 之后,可以开始使用一些现成的 JSONP Web 服务来构建应用程序和 mashup。下面为接下来的开发项目做准备。(提示:您可以复制特定的 URL 并将其粘贴到浏览器的地址栏,以检查生成的 JSONP 响应)。
Digg API:来自 Digg 的头条新闻:
http://services.digg.com/stories/top?appkey=http%3A%2F%2Fmashup.com&type=javascript &callback=? |
Geonames API:邮编的位置信息:
http://www.geonames.org/postalCodeLookupJSON?postalcode=10504&country=US&callback=? |
Flickr API:来自 Flickr 的最新猫图片:
http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any
&format=json&jsoncallback=?
|
Yahoo Local Search API:在邮编为 10504 的地区搜索比萨:
http://local.yahooapis.com/LocalSearchService/V3/localSearch?appid=YahooDemo&query=pizza &zip=10504&results=2&output=json&callback=? |
JSONP 是构建 mashup 的强大技术,但不幸的是,它并不是所有跨域通信需求的万灵药。它有一些缺陷,在提交开发资源之前必须认真考虑它们。第一,也是最重要的一点,没有关于 JSONP 调用的错误处理。如果动态脚本插入有效,就执行调用;如果无效,就静默失败。失败是没有任何提示的。例如,不能从服务器捕捉到 404 错误,也不能取消或重新开始请求。不过,等待一段时间还没有响应的话,就不用理它了。(未来的 jQuery 版本可能有终止 JSONP 请求的特性)。
JSONP 的另一个主要缺陷是被不信任的服务使用时会很危险。因为 JSONP 服务返回打包在函数调用中的 JSON 响应,而函数调用是由浏览器执行的,这使宿主 Web 应用程序更容易受到各类攻击。如果打算使用 JSONP 服务,了解它能造成的威胁非常重要。(参见 参考资料 了解更多信息)。
Win7装memcached和svn自动添加$Id$,$Revision$等keywords (2011-03-24)
最近PHP工作上的两个小技巧,高手不要看了
一.Win7中安装memcached扩展,省去了网上大篇文章,三步即可完成
1.配置apache中的httpd.comf
找到LoadModule mem_cache_module modules/mod_mem_cache.so 把注释去掉
2.配置php.ini 加入memcache扩展
extension=php_memcache.dll
3.将php_memcache.dll复制到\ext扩展目录,重启apache,php就可以了(php_memcache.dll在附件中下载)
二.svn自动添加$Id$,$Revision$等keywords,简单总结步骤如下:
1.右键->settings->General->Subversion->Edit
找到#enable-auto-props = yes 把"#"注释删掉
添加以下配置
*.css = svn:keywords=LastChangedRevision LastChangedBy URL LastChangedDate Id
*.php = svn:keywords=LastChangedRevision LastChangedBy URL LastChangedDate Id
*.html = svn:keywords=LastChangedRevision LastChangedBy URL LastChangedDate Id
*.tpl = svn:keywords=LastChangedRevision LastChangedBy URL LastChangedDate Id
*.txt = svn:keywords=LastChangedRevision LastChangedBy URL LastChangedDate Id
*.js = svn:keywords=LastChangedRevision LastChangedBy URL LastChangedDate Id
这样修改后的效果是吧文件中的$Id$替换成版本等信息
如:$Id$ $LastChangedDate$ 提交后会自动添加版本信息
$Id: test.php 2058 2011-03-24 07:36:55Z wangzhen $
$LastChangedDate: 2011-03-24 15:36:55 +0800 (周四, 24 三月 2011) $
最近工作中遇到的小问题总结 (2011-03-03)
最近工作中遇到的小问题总结
1. PHP GD库生成图片中文乱码
要确保字体支持中文,
有必要进行编码转换$text=iconv( "GBK ", "UTF-8 ",$text);
如果用iconv函数不好使的情况下用
$text1 = mb_convert_encoding($text1, "html-entities","utf-8" );
乱码问题解决
2.MySql 字段类型错误,使用 Cast与Convert函数转换类型
遇到这样的问题,varchar字段排序的时候有错误
SELECT * FROM table ORDER BY user_score DESC
会得到这样的排序,显然是错误的
1
10
2
3
4
5
$sql = "SELECT *,CONVERT(user_score,SIGNED) FROM table
WHERE user_score < {$score}";
二进制,同带binary前缀的效果 : BINARY
字符型,可带参数 : CHAR()
日期 : DATE
时间: TIME
日期时间型 : DATETIME
浮点数 : DECIMAL
整数 : SIGNED
无符号整数 : UNSIGNED
转换类型后问题解决
3.MySql 时间戳存储类型错误
时间戳存了INT类型显然是错误的,不能用DATE_FORMAT函数进行转换时间格式
$sql = "SELECT * , FROM_UNIXTIME( user_time, '%Y-%m-%d' ) AS user_date
FROM table";
使用FROM_UNIXTIME函数问题解决
以上都是一些小问题,但也浪费了一些时间
今后在建立数据字段类型的时候会严格按照类型建立,才不会出这么多问题
PHP和Linux计划任务实现 (2010-11-14)
为了定时更新某一文件,需要程序自动运行,从网上搜到了两种方法:ignore_user_abort() 和crontab
ignore_user_abort()函数搭配set_time_limit(0)和sleep($interval)即可实现程序自动运行更新,下面是一个实例
-
-
<?php
-
ignore_user_abort(); //即使Client断开(如关掉浏览器),PHP脚本也可以继续执行.
-
set_time_limit(0); // 执行时间为无限制,php默认的执行时间是30秒,通过set_time_limit(0)可以让程序无限制的执行下去
-
$interval=60*5; // 每隔5分钟运行
-
do{
-
$fp = fopen('test.txt','a');
-
fwrite($fp,'test');
-
fclose($fp);
-
sleep($interval); // 等待5分钟
-
}while(true);
-
?>
只要运行上面的页面,然后关掉,程序就会一直运行下去。
Linux 下有种更简单的方法,就是crontab命令
crontab命令的功能是在一定的时间间隔调度一些命令的执行。
crontab 使用方法: crontab [ -e | -l | -r ] 文件名 -e:编辑任务 -l:显示任务信息 -r:删除定时执行任务信息
crontab的格式:
* * * * * Command
分 时 日 月 星期 要运行的命令
crontab的例子:
*/5 * * * * lynx http://www.try2.org
每5分钟访问一次 www.try2.org
0 8 * * * lynx http://www.try2.org
每天早上8点访问 www.try2.org
0 10 6 * 1-5 lynx http://www.try2.org
每个月的6号和每个礼拜的星期一到星期五的早上10点访问 www.try2.org
0 5 7 8 * lynx http://www.try2.org
8月7日早上5点访问 www.try2.org
上面几个特殊的意思:
"*"代表所有的取值范围内的数字,"/"代表每的意思,"*/5"表示每5个单位,"-"代表从某个数字到某个数字,","分开几个离散的数字。
PHP通用DES加密算法 (2010-10-11)
与java通用的加密解密方法
-
class Des_Crypt
-
{
-
private $key;
-
-
function __construct($key)
-
{
-
$this->key = $key;
-
}
-
-
function encrypt($string)
-
{
-
$size = mcrypt_get_block_size('des','ecb');
-
$string = mb_convert_encoding($string, 'GBK', 'UTF-8');
-
$string = $this->pkcs5_pad($string, $size);
-
$key = $this->key;
-
$td = mcrypt_module_open('des', '', 'ecb', '');
-
$iv = @mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
-
@mcrypt_generic_init($td, $key, $iv);
-
$data = mcrypt_generic($td, $string);
-
mcrypt_generic_deinit($td);
-
mcrypt_module_close($td);
-
$data = base64_encode($data);
-
return $data;
-
}
-
function decrypt($string)
-
{
-
$string = base64_decode($string);
-
$key =$this->key;
-
$td = mcrypt_module_open('des','','ecb','');
-
//使用MCRYPT_DES算法,cbc模式
-
$iv = @mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
-
$ks = mcrypt_enc_get_key_size($td);
-
@mcrypt_generic_init($td, $key, $iv);
-
//初始处理
-
$decrypted = mdecrypt_generic($td, $string);
-
//解密
-
mcrypt_generic_deinit($td);
-
//结束
-
mcrypt_module_close($td);
-
-
$result = $this->pkcs5_unpad($decrypted);
-
$result = mb_convert_encoding($result, 'UTF-8', 'GBK');
-
return $result;
-
}
-
function pkcs5_pad ($text, $blocksize)
-
{
-
$pad = $blocksize - (strlen($text) % $blocksize);
-
return $text . str_repeat(chr($pad), $pad);
-
}
-
function pkcs5_unpad($text)
-
{
-
$pad = ord($text{strlen($text)-1});
-
if ($pad > strlen($text))
-
{
-
return false;
-
}
-
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad)
-
{
-
return false;
-
}
-
return substr($text, 0, -1 * $pad);
-
}
-
}
-
/*
-
For example:
-
-
$key = "!@#%test";
-
$string1 = "13701014606";
-
$string2 = "这是中文测试";
-
$des = new Des_Crypt($key);
-
-
$encryption = $des->encrypt($string2);
-
$decryption = $des->decrypt($encryption);
-
-
echo "原始值:".$decryption;
-
echo "<br />";
-
echo "加密值:".$encryption;
-
*/
PHP获取手机相关信息 (2010-09-15)
该PHP操作类实现获取手机号
手机头信息,取UA,取得手机类型,判断是否是opera,判断是否是m3gate,取得HA,取得手机IP
代码如下:
-
<?php
-
/**
-
* @desc 手机操作类 获取手机相关信息
-
* @since version - 2010-9-16上午12:21:00 edit
-
*/
-
class mobile {
-
/**
-
* 函数名称: getPhoneNumber
-
* 函数功能: 取手机号
-
* 输入参数: none
-
* 函数返回值: 成功返回号码,失败返回false
-
* 其它说明: 说明
-
*/
-
public function getPhoneNumber() {
-
if (isset($_SERVER['HTTP_X_NETWORK_INFO'])) {
-
$str1 = $_SERVER['HTTP_X_NETWORK_INFO'];
-
$getstr1 = preg_replace('/(.*,)(11[d])(,.*)/i',"",$str1);
-
Return $getstr1;
-
}
-
elseif (isset($_SERVER['HTTP_X_UP_CALLING_LINE_ID'])) {
-
$getstr2 = $_SERVER['HTTP_X_UP_CALLING_LINE_ID'];
-
Return $getstr2;
-
}
-
elseif (isset($_SERVER['HTTP_X_UP_SUBNO'])) {
-
$str3 = $_SERVER['HTTP_X_UP_SUBNO'];
-
$getstr3 = preg_replace('/(.*)(11[d])(.*)/i',"",$str3);
-
Return $getstr3;
-
}
-
elseif (isset($_SERVER['DEVICEID'])) {
-
Return $_SERVER['DEVICEID'];
-
}
-
else {
-
Return false;
-
}
-
}
-
-
/**
-
* 函数名称: getHttpHeader
-
* 函数功能: 取头信息
-
* 输入参数: none
-
* 函数返回值: 成功返回号码,失败返回false
-
* 其它说明: 说明
-
*/
-
public function getHttpHeader() {
-
$str = "";
-
foreach ($_SERVER as $key=>$val) {
-
$gstr = str_replace("&","&",$val);
-
$str.= "$key -> ".$gstr."rn";
-
}
-
Return $str;
-
}
-
-
/**
-
* 函数名称: getUA
-
* 函数功能: 取UA
-
* 输入参数: none
-
* 函数返回值: 成功返回号码,失败返回false
-
* 其它说明: 说明
-
*/
-
public function getUA() {
-
if (isset($_SERVER['HTTP_USER_AGENT'])) {
-
Return $_SERVER['HTTP_USER_AGENT'];
-
}
-
else {
-
Return false;
-
}
-
}
-
-
/**
-
* 函数名称: getPhoneType
-
* 函数功能: 取得手机类型
-
* 输入参数: none
-
* 函数返回值: 成功返回string,失败返回false
-
* 其它说明: 说明
-
*/
-
public function getPhoneType() {
-
$ua = $this->getUA();
-
if($ua!=false) {
-
$str = explode(" ",$ua);
-
Return $str[0];
-
}
-
else {
-
Return false;
-
}
-
}
-
-
/**
-
* 函数名称: isOpera
-
* 函数功能: 判断是否是opera
-
* 输入参数: none www.knowsky.com
-
* 函数返回值: 成功返回string,失败返回false
-
* 其它说明: 说明
-
*/
-
public function isOpera() {
-
$uainfo = $this->getUA();
-
if (preg_match('/.*Opera.*/i',$uainfo)) {
-
Return true;
-
}
-
else {
-
Return false;
-
}
-
}
-
-
/**
-
* 函数名称: isM3gate
-
* 函数功能: 判断是否是m3gate
-
* 输入参数: none
-
* 函数返回值: 成功返回string,失败返回false
-
* 其它说明: 说明
-
*/
-
public function isM3gate() {
-
$uainfo = $this->getUA();
-
if (preg_match('/M3Gate/i',$uainfo)) {
-
Return true;
-
}
-
else {
-
Return false;
-
}
-
}
-
-
/**
-
* 函数名称: getHttpAccept
-
* 函数功能: 取得HA
-
* 输入参数: none
-
* 函数返回值: 成功返回string,失败返回false
-
* 其它说明: 说明
-
*/
-
public function getHttpAccept() {
-
if (isset($_SERVER['HTTP_ACCEPT'])) {
-
Return $_SERVER['HTTP_ACCEPT'];
-
}
-
else {
-
Return false;
-
}
-
}
-
-
/**
-
* 函数名称: getIP
-
* 函数功能: 取得手机IP
-
* 输入参数: none
-
* 函数返回值: 成功返回string
-
* 其它说明: 说明
-
*/
-
public function getIP() {
-
$ip=getenv('REMOTE_ADDR');
-
$ip_ = getenv('HTTP_X_FORWARDED_FOR');
-
if (($ip_ != "") && ($ip_ != "unknown")) {
-
$ip=$ip_;
-
}
-
return $ip;
-
}
-
}
-
?>
PHP中的SOAP请求Webserver (2010-09-08)
1 预定义类
SoapClient
SoapFault
SoapHeader (low level)
SoapParam (low level)
SoapServer
SoapVar (low level)
2 SOAP 服务在 PHP 中的工作方式
2.1 首先,创建一个Soap Server。
$server = new SoapServer($wsdl [, $options]);
其中,$wsdl 是描述托管服务的 Web 服务描述语言 (WSDL) 文档的位置;$options 是一组键/值对,其中包含了在创建服务时需要考虑的所有设置选项。这些选项包括:
encoding:用于该 SOAP 服务的字符编码(即字符串 ISO-8859-1)。
actor:该 SOAP 服务的角色 URI。
classmap:将 WSDL 数据类型映射到 PHP 中的类名的一组键/值对本身。如果使用该选项,PHP 将根据 WSDL 中定义的类型将这些类呈现给连接客户端。
例:使用名为 bookman.wsdl 的 WSDL 文档创建一个使用 SOAP v1.2 协议的 SOAP 服务。
$server = new SoapServer(“bookman.wsdl”, array(‘soap_version’ => SOAP_1_2));
2.2 下一步,创建服务方法。
function f1($a, $b) { ... }
function f2($a, $b) { ... }
...
注册可以写成:
$server->addFunction(‘f1’);
$server->addFunction(‘f2’);
或者,
$server->addFunction(array(‘f1’, ‘f2’));
或者,
$server->addFunction(SOAP_FUNCTIONS_ALL);
也可以以面向对象的方法:(推荐这种方法!)
class functions {
public function f1($a, $b) { ... }
public function f2($a, $b) { ... }
}
$server->setClass("functions");
要完成SOAP服务器,还必须使用handle()函数开始处理从连接的 SOAP 客户端传入的请求。完整示例:
class functions {
public function f1($a, $b) { ... }
public function f2($a, $b) { ... }
}
$server = new SoapServer(“bookman.wsdl”, array(‘soap_version’ => SOAP_1_2));
$server->setClass("functions");
$server->handle();
2.3 错误报告:
public function div($a, $b) {
if($b == 0) {
throw new SoapFault(-1, “Cannot divide by zero!”); // 不然要SoapFault这个类干啥
}
return $a / $b;
}
2.4 上面还有一个WSDL的问题没解决,如何生成一个WSDL文档呢?使用Zend Studio的做法如下:
要正确使用元数据注释。比如:
/**
* Add two integers together
*
* @param integer $a The first integer of the addition
* @param integer $b The second integer of the addition
* @return integer The sum of the provided integers
*/
public function add($a, $b) {
return $a + $b;
}
然后使用Tools菜单下的WSDL生成器就可以了。当然必须将WSDL文档放在服务器能够访问的位置。(那还用说,呵呵)
2.5 用PHP创建SOAP客户端,以使用SOAP服务
$client = new SoapClient($wsdl [, $options]);
$wsdl 参数是要访问服务的 WSDL 文档的位置,可选参数 $options 是配置客户端连接的一组键/值对。包括以下一些可用选项:
soap_version:要使用的 SOAP 协议版本,其值为常量 SOAP_1_1 或 SOAP_1_2
login:如果在 SOAP 服务器上使用 HTTP 身份验证,这是要使用的登录名
password:如果在 SOAP 服务器上使用 HTTP 身份验证,这是要使用的密码
proxy_host:如果通过代理服务器连接,这是服务器的地址
proxy_port:如果通过代理服务器连接,这是代理监听的端口
proxy_login:如果通过代理服务器连接,这是登录时使用的用户名
proxy_password:如果通过代理服务器连接,这是登录时使用的密码
local_cert:如果连接到一个通过安全 HTTP (https) 通信的 SOAP 服务器,这是本地认证文件的位置
passphrase:与 local_cert 结合使用,以提供认证文件的密码短语(如果有)
compression:如果设置为 true,PHP 将尝试使用压缩的 HTTP 请求与 SOAP 服务器通信
classmap:将 WSDL 数据类型映射到 PHP 类以便在客户端使用的一组键/值对
如果PHP中的SOAP客户端通过指定的WSDL文档实例化,就可以使用返回的客户端对象调用在 SOAP 服务器上公开的方法,就好像它们是自带 PHP 调用,并处理任何可能作为原生 PHP 异常发生的 SOAP 错误。
示例:
$client = new SoapClient(“http://www.example.com/math.wsdl”);
try {
$result = $client->div(10,rand(0,5); // will cause a Soap Fault if divide by zero
print “The answer is: $result”;
} catch(SoapFault $e) {
print “Sorry an error was caught executing your request: {$e->getMessage()}”;
}
2.6 一些说明
如果在创建SOAP服务器端和客户端的时候,传入的WSDL文档URI为NULL,则工作在non-Wsdl方式下。
工作在non-Wsdl方式下的时候,server端构造函数中的option参数需指定uri(只作xml名字空间用,和真实uri无关)client的option参数需指定uri(解释同前)和location(server端真实url)参数。
PHP手册中,对于SoapClient类的第二个参数options的说明如下:
array options:
An array of options. If working in WSDL mode, this parameter is optional. If working in non-WSDL mode, you must set the location and uri options, where location is the URL to request and uri is the target namespace of the SOAP service.
The style and use options only work in non-WSDL mode. In WSDL mode, they come from the WSDL file.
The soap_version option specifies whether to use SOAP 1.1, or SOAP 1.2 client.
For HTTP authentication, you may use the login and password options. For making an HTTP connection through a proxy server, use the options proxy_host, proxy_port, proxy_login and proxy_password. For HTTPS client certificate authentication use local_cert and passphrase options.
The compression option allows to use compression of HTTP SOAP requests and responses.
The encoding option defines internal character encoding. This option does not change the encofing of SOAP requests (it is always utf-8), but converts strings into it.
The classmap option can be used to map some WSDL types to PHP classes. This option must be an array with WSDL types as keys and names of PHP classes as values.
The trace and exceptions options are useful for debuging purpos

牛。。求源码分享,正在学习中,,