分类 程序开发 下的文章

php读取ms sql server数据的方法和注意事项

在windows平台,php5.3+读取sql server里面的数据,其实用php_pdo_odbc.dll扩展是最好的选择,SQL语句的兼容性很高,比ms自家出品的sqlsrv(Microsoft Drivers for PHP for SQL Server)扩展强太多了。

一、下面先吐槽一下sqlsrv一些不爽的地方:

1、获取的数据编码默认是UTF-8的,想改为其它编码的数据有点麻烦,虽说它可以设为用系统的编码,但是这里有个很大的问题, 假如你的系统是gbk的,但是获取到的数据有些还是会变为UTF-8的。尽管可以用iconv转换编码,但这个iconv本来就不能转换全部的中文,说不定某些中文就被忽略掉了,不敢用iconv转换成GBK的。

2、某些字段的类型不能自动映射,会出现映射错误,提示数据类型不正确。

3、一些复杂点的SQL语句居然查询不到结果,这个相当无语了,我的SQL语句中出现了中文,居然都返回不了查询结果,不知道是不是编码问题,我也不想测试了。还有个非常奇怪的地方,SQL语句里面用到了ISNULL这个函数,它居然也不执行,取不到任何结果。

总的来说这个东西只能用来处理下英文类的数据,简单点的SQL语句。复杂点的它根本就不行,兼容性太差。

二、用php_pdo_odbc.dll可以很轻松的处理复杂SQL语句及编码问题。当然用pdo_odbc也出现了一点应该注意的问题,不然我也不会在这里吐槽了。读取nvarchar或者nchar字段的数据时,可能会把该字段后面部分的中文给弄成乱码。因为nvarchar字段是按字符存储的,而odbc是按字节读取的,它好像不能处理多字节字符。当它读取到字段长度那么多个字节的时候,后面的字节就被它搞成乱码了,一开始这个问题百思不得其解。有什么办法可以让它不乱码呢,其实你只需要用convert转换一下数据类型为varchar就行了。如:select convert(varchar(两倍的nvarchar字段的长度), nvarchar字段名) from table1。varchar一定要带长度,最好是这个nvarchar字段长度的两倍,这样转换一下后,你获取的数据就不会出现乱码了。

nginx里面codeigniter的重写规则

有下面几种方法

一、使用QUERY_STRING,这个最简单了,nginx里面配置少,性能也应该最好

修改codeinniter里面的application/config/config.php文件,改为如下:

$config['uri_protocol'] = 'QUERY_STRING';

nginx里面这样配置一下就行了

if  (!-f $request_filename) {
rewrite (.+) /index.php?$1 last;
}

二、使用PATH_INFO,由于nginx里面默认是不识别PATH_INFO这个php变量的,它会把PATH_INFO作为一个路径,这样就出现了404错误

修改codeinniter里面的application/config/config.php文件,改为如下:

$config['uri_protocol'] = 'PATH_INFO';

nginx里面加两段代码:

location ~ \.php($|/) {
fastcgi_pass 127.0.0.1:9000;
include fastcgi.conf;
#下面3行让nginx正确识别文件路径和PATH_INFO
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
}

if  (!-f $request_filename) {
rewrite (.+) /index.php$1 last;
}

三、使用REQUEST_URI,这个个人觉得没有使用QUERY_STRING来的方便,不利于二次URL重写,毕竟某些时候你想把CodeIgniter默认重写的URL再次重写为比较短点的,这个时候你就必须用CI的config里面enable_query_strings这个地方配置的查询字符串来rewrite了,感觉有点麻烦,如果你不用二次重写,使用这个方法也很简单的。

修改codeinniter里面的application/config/config.php文件,改为如下:

$config['uri_protocol'] = 'REQUEST_URI';

nginx里面这样配置一下就行了

if  (!-f $request_filename) {
rewrite .+ /index.php last;
}

PHP字符串加密解密函数

[code language="php"]
function encrypt( $string, $operation = 'DECODE', $key = '', $expiry = 3600 ){

$ckey_length = 4;
// 随机密钥长度 取值 0-32;
// 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,增大破解难度。
// 取值越大,密文变动规律越大,密文变化 = 16 的 $ckey_length 次方
// 当此值为 0 时,则不产生随机密钥
$key = md5( $key ? $key : 'default_key' ); //这里可以填写默认key值
$keya = md5( substr( $key, 0, 16 ) );
$keyb = md5( substr( $key, 16, 16 ) );
$keyc = $ckey_length ? ( $operation == 'DECODE' ? substr( $string, 0, $ckey_length ): substr( md5( microtime() ), - $ckey_length ) ) : '';

$cryptkey = $keya . md5( $keya . $keyc );
$key_length = strlen( $cryptkey );

$string = $operation == 'DECODE' ? base64_decode( substr( $string, $ckey_length ) ) : sprintf( '%010d', $expiry ? $expiry + time() : 0 ) . substr( md5( $string . $keyb ), 0, 16 ) . $string;
$string_length = strlen( $string );

$result = '';
$box = range( 0, 255 );

$rndkey = array();
for( $i = 0; $i <= 255; $i++ ){
$rndkey[$i] = ord( $cryptkey[$i % $key_length] );
}

for( $j = $i = 0; $i < 256; $i++ ){
$j = ( $j + $box[$i] + $rndkey[$i] ) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}

for( $a = $j = $i = 0; $i < $string_length; $i++ ){
$a = ( $a + 1 ) % 256;
$j = ( $j + $box[$a] ) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr( ord( $string[$i] ) ^ ( $box[( $box[$a] + $box[$j] ) % 256] ) );
}

if( $operation == 'DECODE' ){
if( ( substr( $result, 0, 10 ) == 0 || substr( $result, 0, 10 ) - time() > 0 ) && substr( $result, 10, 16 ) == substr( md5( substr( $result, 26 ) . $keyb ), 0, 16 ) ){
return substr( $result, 26 );
}else{
return '';
}
}else{
return $keyc . str_replace( '=', '', base64_encode( $result ) );
}
}
[/code]

fsockopen返回gzip内容无法gzdecode解压的问题

#1.返回头Transfer-Encoding: chunked表明是chunked的传输编码
这个意思是,服务器分批把http body返回给你,比如http body如下
2 --表示下一个chunked的长度为2,这个数字是16进制,不是10进制
ab -- 长度为2的串
3 -- 同上
abc -- 长度为3的串
1 -- 同上
a -- 长度为1的串
0 -- 长度为0,这个是结束标识

所以最终的http body应该是ababca ,长度标识是不需要的。

- 阅读剩余部分 -

php中flush()在iis7下无效的解决方法

在一个比较费时的操作中,想把操作记录在浏览器上实时显示出来,用到了flush(),把缓冲中的内容发送到浏览器。但在iis7里面用fastcgi模式配置的php怎么都实现不了,结果总是一起显示出来。

[code language="php"]
for ($i=10; $i>0; $i--)
{
echo $i.'<br />';
@ob_flush();
flush();
sleep(1);
}
[/code]

- 阅读剩余部分 -

PHP线程安全与非线程安全的区别

Windows版的PHP从版本5.2.1开始有Thread Safe(线程安全)和None Thread Safe(NTS,非线程安全)之分,这两者不同在于何处?到底应该用哪种?这里做一个简单的介绍。

从2000年10月20日发布的第一个Windows版的PHP3.0.17开始的都是线程安全的版本,这是由于与Linux/Unix系统是采用多进程的工作方式不同的是Windows系统是采用多线程的工作方式。如果在IIS下以CGI方式运行PHP会非常慢,这是由于CGI模式是建立在多进程的基础之上的,而非多线程。一般我们会把PHP配置成以ISAPI的方式来运行,ISAPI是多线程的方式,这样就快多了。但存在一个问题,很多常用的PHP扩展是以Linux/Unix的多进程思想来开发的,这些扩展在ISAPI的方式运行时就会出错搞垮IIS。因此在IIS下CGI模式才是 PHP运行的最安全方式,但CGI模式对于每个HTTP请求都需要重新加载和卸载整个PHP环境,其消耗是巨大的。

为了兼顾IIS下PHP的效率和安全,微软给出了FastCGI的解决方案。FastCGI可以让PHP的进程重复利用而不是每一个新的请求就重开一个进程。同时FastCGI也可以允许几个进程同时执行。这样既解决了CGI进程模式消耗太大的问题,又利用上了CGI进程模式不存在线程安全问题的优势。

因此,如果是使用ISAPI的方式来运行PHP就必须用Thread Safe(线程安全)的版本;而用FastCGI模式运行PHP的话就没有必要用线程安全检查了,用None Thread Safe(NTS,非线程安全)的版本能够更好的提高效率。

TS是线程安全(Thread Safe ),一般Apache模块、IIS的ISAPI需要使用。
NTS是无线程安全的(Non Thread Safe ),因为php-cgi不需要。
此外还分VC6和VC9,vc6是给Apache用的,vc9是给IIS用的。VC9需要安装 c++2008运行库。

curl获取的header中出现HTTP/1.1 100 continue的问题

用curl获取返回结果的头的第一行出现了“

HTTP/1.1 100 continue

”,之后才是HTTP/1.1 200 OK之类的真实状态。出现这个问题是因为curl默认发送了这样的一个header:“Expect: 100-continue”,我们只需要把这个header重写下就可以了。

curl_setopt( $curl_handle, CURLOPT_HTTPHEADER, array( 'Expect:' ) );

加一个Expect:后面为空,这样就把curl默认发送的那个header覆盖了,ok,问题解决。

json_encode转换中文为null的问题

把要转换的数组先urlencode一下就好了,json化后再urldecode下。

[code language="php"]
<?php

$data = array(
'game' => '冰火国度',
'name' => '刺之灵',
'country' => '冰霜国',
'level' => 45
);

/**
* 处理json_encode乱码
*/
$newData = array();
foreach( $data as $key => $value )
{
$newData[ $key ] = urlencode( $value );
}
echo urldecode( json_encode( $newData ) );

?>
[/code]

VS2008里调试出错:打开的 URL 的 IIS 辅助进程当前没有运行

把网站设置到IIS里面运行,然后F5调试,出现如下的错误:

无法在 Web 服务器上启动调试。打开的 URL 的 IIS 辅助进程当前没有运行。

英文描述:

Unable to start debugging on the Web server.  The IIS worker process for the launched URL is not currently running.

折腾了半天,还是在国外的网站上面找到了解决方法,原来是因为我的电脑出现了两个本地IP,在IIS里建立网站的时候就随便选了一个IP,只要把这个IP地址选择为“全部未分配”,就是“*”就可以调试了。就是绑定域名那里选择IP的时候不能用固定的,不选择IP就行了。